OpenStack Networking (Neutron)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2854 lines
131KB

  1. # Copyright (c) 2013 OpenStack Foundation
  2. # All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. import functools
  16. import fixtures
  17. import mock
  18. import netaddr
  19. from neutron_lib.api.definitions import availability_zone as az_def
  20. from neutron_lib.api.definitions import external_net as extnet_apidef
  21. from neutron_lib.api.definitions import portbindings
  22. from neutron_lib.api.definitions import provider_net as pnet
  23. from neutron_lib.callbacks import events
  24. from neutron_lib.callbacks import exceptions as c_exc
  25. from neutron_lib.callbacks import registry
  26. from neutron_lib.callbacks import resources
  27. from neutron_lib import constants
  28. from neutron_lib import context
  29. from neutron_lib import exceptions as exc
  30. from neutron_lib.plugins import constants as plugin_constants
  31. from neutron_lib.plugins import directory
  32. from neutron_lib.plugins.ml2 import api as driver_api
  33. from oslo_config import cfg
  34. from oslo_db import exception as db_exc
  35. from oslo_utils import uuidutils
  36. import testtools
  37. import webob
  38. from neutron._i18n import _
  39. from neutron.common import utils
  40. from neutron.db import agents_db
  41. from neutron.db import api as db_api
  42. from neutron.db import models_v2
  43. from neutron.db import provisioning_blocks
  44. from neutron.db import segments_db
  45. from neutron.extensions import multiprovidernet as mpnet
  46. from neutron.objects import base as base_obj
  47. from neutron.objects import router as l3_obj
  48. from neutron.plugins.ml2.common import exceptions as ml2_exc
  49. from neutron.plugins.ml2 import db as ml2_db
  50. from neutron.plugins.ml2 import driver_context
  51. from neutron.plugins.ml2.drivers import type_vlan
  52. from neutron.plugins.ml2 import managers
  53. from neutron.plugins.ml2 import models
  54. from neutron.plugins.ml2 import plugin as ml2_plugin
  55. from neutron.services.revisions import revision_plugin
  56. from neutron.services.segments import db as segments_plugin_db
  57. from neutron.services.segments import plugin as segments_plugin
  58. from neutron.tests.common import helpers
  59. from neutron.tests.unit import _test_extension_portbindings as test_bindings
  60. from neutron.tests.unit.agent import test_securitygroups_rpc as test_sg_rpc
  61. from neutron.tests.unit.db import test_allowedaddresspairs_db as test_pair
  62. from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
  63. from neutron.tests.unit.db import test_ipam_pluggable_backend as test_ipam
  64. from neutron.tests.unit.extensions import test_extra_dhcp_opt as test_dhcpopts
  65. from neutron.tests.unit.plugins.ml2.drivers import mechanism_logger as \
  66. mech_logger
  67. from neutron.tests.unit.plugins.ml2.drivers import mechanism_test as mech_test
  68. cfg.CONF.import_opt('network_vlan_ranges',
  69. 'neutron.plugins.ml2.drivers.type_vlan',
  70. group='ml2_type_vlan')
  71. PLUGIN_NAME = 'ml2'
  72. DEVICE_OWNER_COMPUTE = constants.DEVICE_OWNER_COMPUTE_PREFIX + 'fake'
  73. HOST = 'fake_host'
  74. TEST_ROUTER_ID = 'router_id'
  75. # TODO(marun) - Move to somewhere common for reuse
  76. class PluginConfFixture(fixtures.Fixture):
  77. """Plugin configuration shared across the unit and functional tests."""
  78. def __init__(self, plugin_name, parent_setup=None):
  79. super(PluginConfFixture, self).__init__()
  80. self.plugin_name = plugin_name
  81. self.parent_setup = parent_setup
  82. def _setUp(self):
  83. if self.parent_setup:
  84. self.parent_setup()
  85. class Ml2ConfFixture(PluginConfFixture):
  86. def __init__(self, parent_setup=None):
  87. super(Ml2ConfFixture, self).__init__(PLUGIN_NAME, parent_setup)
  88. class Ml2PluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
  89. _mechanism_drivers = ['logger', 'test']
  90. l3_plugin = ('neutron.tests.unit.extensions.test_l3.'
  91. 'TestL3NatServicePlugin')
  92. def get_additional_service_plugins(self):
  93. """Subclasses can return a dictionary of service plugins to load."""
  94. return {}
  95. def setup_parent(self):
  96. """Perform parent setup with the common plugin configuration class."""
  97. service_plugins = {'l3_plugin_name': self.l3_plugin}
  98. service_plugins.update(self.get_additional_service_plugins())
  99. # Ensure that the parent setup can be called without arguments
  100. # by the common configuration setUp.
  101. parent_setup = functools.partial(
  102. super(Ml2PluginV2TestCase, self).setUp,
  103. plugin=PLUGIN_NAME,
  104. service_plugins=service_plugins,
  105. )
  106. self.useFixture(Ml2ConfFixture(parent_setup))
  107. self.port_create_status = 'DOWN'
  108. def setUp(self):
  109. self.ovo_push_interface_p = mock.patch(
  110. 'neutron.plugins.ml2.ovo_rpc.OVOServerRpcInterface')
  111. self.ovo_push_interface_p.start()
  112. # Enable the test mechanism driver to ensure that
  113. # we can successfully call through to all mechanism
  114. # driver apis.
  115. cfg.CONF.set_override('mechanism_drivers',
  116. self._mechanism_drivers,
  117. group='ml2')
  118. self.physnet = 'physnet1'
  119. self.vlan_range = '1:100'
  120. self.vlan_range2 = '200:300'
  121. self.physnet2 = 'physnet2'
  122. self.phys_vrange = ':'.join([self.physnet, self.vlan_range])
  123. self.phys2_vrange = ':'.join([self.physnet2, self.vlan_range2])
  124. cfg.CONF.set_override('network_vlan_ranges',
  125. [self.phys_vrange, self.phys2_vrange],
  126. group='ml2_type_vlan')
  127. self.setup_parent()
  128. self.driver = directory.get_plugin()
  129. self.context = context.get_admin_context()
  130. class TestMl2BulkToggleWithoutBulkless(Ml2PluginV2TestCase):
  131. _mechanism_drivers = ['logger', 'test']
  132. def test_bulk_enabled_with_bulk_drivers(self):
  133. self.assertFalse(self._skip_native_bulk)
  134. class TestMl2BasicGet(test_plugin.TestBasicGet,
  135. Ml2PluginV2TestCase):
  136. pass
  137. class TestMl2V2HTTPResponse(test_plugin.TestV2HTTPResponse,
  138. Ml2PluginV2TestCase):
  139. pass
  140. class TestMl2NetworksV2(test_plugin.TestNetworksV2,
  141. Ml2PluginV2TestCase):
  142. def setUp(self, plugin=None):
  143. super(TestMl2NetworksV2, self).setUp()
  144. # provider networks
  145. self.pnets = [{'name': 'net1',
  146. pnet.NETWORK_TYPE: 'vlan',
  147. pnet.PHYSICAL_NETWORK: 'physnet1',
  148. pnet.SEGMENTATION_ID: 1,
  149. 'tenant_id': 'tenant_one'},
  150. {'name': 'net2',
  151. pnet.NETWORK_TYPE: 'vlan',
  152. pnet.PHYSICAL_NETWORK: 'physnet2',
  153. pnet.SEGMENTATION_ID: 210,
  154. 'tenant_id': 'tenant_one'},
  155. {'name': 'net3',
  156. pnet.NETWORK_TYPE: 'vlan',
  157. pnet.PHYSICAL_NETWORK: 'physnet2',
  158. pnet.SEGMENTATION_ID: 220,
  159. 'tenant_id': 'tenant_one'}
  160. ]
  161. # multiprovider networks
  162. self.mp_nets = [{'name': 'net4',
  163. mpnet.SEGMENTS:
  164. [{pnet.NETWORK_TYPE: 'vlan',
  165. pnet.PHYSICAL_NETWORK: 'physnet2',
  166. pnet.SEGMENTATION_ID: 1},
  167. {pnet.NETWORK_TYPE: 'vlan',
  168. pnet.PHYSICAL_NETWORK: 'physnet2',
  169. pnet.SEGMENTATION_ID: 202}],
  170. 'tenant_id': 'tenant_one'}
  171. ]
  172. self.nets = self.mp_nets + self.pnets
  173. def test_network_after_create_callback(self):
  174. after_create = mock.Mock()
  175. registry.subscribe(after_create, resources.NETWORK,
  176. events.AFTER_CREATE)
  177. with self.network() as n:
  178. after_create.assert_called_once_with(
  179. resources.NETWORK, events.AFTER_CREATE, mock.ANY,
  180. context=mock.ANY, network=mock.ANY)
  181. kwargs = after_create.mock_calls[0][2]
  182. self.assertEqual(n['network']['id'],
  183. kwargs['network']['id'])
  184. def test_network_precommit_create_callback(self):
  185. precommit_create = mock.Mock()
  186. registry.subscribe(precommit_create, resources.NETWORK,
  187. events.PRECOMMIT_CREATE)
  188. with self.network():
  189. precommit_create.assert_called_once_with(
  190. resources.NETWORK, events.PRECOMMIT_CREATE, mock.ANY,
  191. context=mock.ANY, network=mock.ANY, request=mock.ANY)
  192. def test_network_precommit_create_callback_aborts(self):
  193. precommit_create = mock.Mock()
  194. registry.subscribe(precommit_create, resources.NETWORK,
  195. events.PRECOMMIT_CREATE)
  196. precommit_create.side_effect = exc.InvalidInput(error_message='x')
  197. data = {'network': {'tenant_id': 'sometenant', 'name': 'dummy',
  198. 'admin_state_up': True, 'shared': False}}
  199. req = self.new_create_request('networks', data)
  200. res = req.get_response(self.api)
  201. self.assertEqual(400, res.status_int)
  202. def test_network_precommit_update_includes_req(self):
  203. precommit_update = mock.Mock()
  204. registry.subscribe(precommit_update, resources.NETWORK,
  205. events.PRECOMMIT_UPDATE)
  206. with self.network() as n:
  207. data = {'network': {'name': 'updated'}}
  208. req = self.new_update_request('networks', data, n['network']['id'])
  209. self.deserialize(self.fmt, req.get_response(self.api))
  210. precommit_update.assert_called_once_with(
  211. resources.NETWORK, events.PRECOMMIT_UPDATE, mock.ANY,
  212. context=mock.ANY, network=mock.ANY, original_network=mock.ANY,
  213. request=mock.ANY)
  214. def test_network_after_update_callback(self):
  215. after_update = mock.Mock()
  216. registry.subscribe(after_update, resources.NETWORK,
  217. events.AFTER_UPDATE)
  218. with self.network() as n:
  219. data = {'network': {'name': 'updated'}}
  220. req = self.new_update_request('networks', data, n['network']['id'])
  221. self.deserialize(self.fmt, req.get_response(self.api))
  222. after_update.assert_called_once_with(
  223. resources.NETWORK, events.AFTER_UPDATE, mock.ANY,
  224. context=mock.ANY, network=mock.ANY, original_network=mock.ANY)
  225. kwargs = after_update.mock_calls[0][2]
  226. self.assertEqual(n['network']['name'],
  227. kwargs['original_network']['name'])
  228. self.assertEqual('updated', kwargs['network']['name'])
  229. def test_network_after_delete_callback(self):
  230. after_delete = mock.Mock()
  231. registry.subscribe(after_delete, resources.NETWORK,
  232. events.AFTER_DELETE)
  233. with self.network() as n:
  234. req = self.new_delete_request('networks', n['network']['id'])
  235. req.get_response(self.api)
  236. after_delete.assert_called_once_with(
  237. resources.NETWORK, events.AFTER_DELETE, mock.ANY,
  238. context=mock.ANY, network=mock.ANY)
  239. kwargs = after_delete.mock_calls[0][2]
  240. self.assertEqual(n['network']['id'],
  241. kwargs['network']['id'])
  242. def test_bulk_network_before_and_after_events_outside_of_txn(self):
  243. # capture session states during each before and after event
  244. before = []
  245. after = []
  246. b_func = lambda *a, **k: before.append(k['context'].session.is_active)
  247. a_func = lambda *a, **k: after.append(k['context'].session.is_active)
  248. registry.subscribe(b_func, resources.NETWORK, events.BEFORE_CREATE)
  249. registry.subscribe(a_func, resources.NETWORK, events.AFTER_CREATE)
  250. data = [{'tenant_id': self._tenant_id}] * 4
  251. self._create_bulk_from_list(
  252. self.fmt, 'network', data, context=context.get_admin_context())
  253. # ensure events captured
  254. self.assertTrue(before)
  255. self.assertTrue(after)
  256. # ensure session was closed for all
  257. self.assertFalse(any(before))
  258. self.assertFalse(any(after))
  259. def _create_and_verify_networks(self, networks):
  260. for net_idx, net in enumerate(networks):
  261. # create
  262. req = self.new_create_request('networks',
  263. {'network': net})
  264. # verify
  265. network = self.deserialize(self.fmt,
  266. req.get_response(self.api))['network']
  267. if mpnet.SEGMENTS not in net:
  268. for k, v in net.items():
  269. self.assertEqual(net[k], network[k])
  270. self.assertNotIn(mpnet.SEGMENTS, network)
  271. else:
  272. segments = network[mpnet.SEGMENTS]
  273. expected_segments = net[mpnet.SEGMENTS]
  274. self.assertEqual(len(expected_segments), len(segments))
  275. for expected, actual in zip(expected_segments, segments):
  276. self.assertEqual(expected, actual)
  277. def _lookup_network_by_segmentation_id(self, seg_id, num_expected_nets):
  278. params_str = "%s=%s" % (pnet.SEGMENTATION_ID, seg_id)
  279. net_req = self.new_list_request('networks', None,
  280. params=params_str)
  281. networks = self.deserialize(self.fmt, net_req.get_response(self.api))
  282. if num_expected_nets:
  283. self.assertIsNotNone(networks)
  284. self.assertEqual(num_expected_nets, len(networks['networks']))
  285. else:
  286. self.assertIsNone(networks)
  287. return networks
  288. def test_list_networks_with_segmentation_id(self):
  289. self._create_and_verify_networks(self.pnets)
  290. # verify we can find the network that we expect
  291. lookup_vlan_id = 1
  292. expected_net = [n for n in self.pnets
  293. if n[pnet.SEGMENTATION_ID] == lookup_vlan_id].pop()
  294. networks = self._lookup_network_by_segmentation_id(lookup_vlan_id, 1)
  295. # verify all provider attributes
  296. network = networks['networks'][0]
  297. for attr in pnet.ATTRIBUTES:
  298. self.assertEqual(expected_net[attr], network[attr])
  299. def test_list_mpnetworks_with_segmentation_id(self):
  300. self._create_and_verify_networks(self.nets)
  301. # get all networks with seg_id=1 (including multisegment networks)
  302. lookup_vlan_id = 1
  303. networks = self._lookup_network_by_segmentation_id(lookup_vlan_id, 2)
  304. # get the mpnet
  305. networks = [n for n in networks['networks'] if mpnet.SEGMENTS in n]
  306. network = networks.pop()
  307. # verify attributes of the looked up item
  308. segments = network[mpnet.SEGMENTS]
  309. expected_segments = self.mp_nets[0][mpnet.SEGMENTS]
  310. self.assertEqual(len(expected_segments), len(segments))
  311. for expected, actual in zip(expected_segments, segments):
  312. self.assertEqual(expected, actual)
  313. def test_create_network_segment_allocation_fails(self):
  314. plugin = directory.get_plugin()
  315. mock.patch.object(db_api._retry_db_errors, 'max_retries',
  316. new=2).start()
  317. with mock.patch.object(
  318. plugin.type_manager, 'create_network_segments',
  319. side_effect=db_exc.RetryRequest(ValueError())
  320. ) as f:
  321. data = {'network': {'tenant_id': 'sometenant', 'name': 'dummy',
  322. 'admin_state_up': True, 'shared': False}}
  323. req = self.new_create_request('networks', data)
  324. res = req.get_response(self.api)
  325. self.assertEqual(500, res.status_int)
  326. # 1 + retry count
  327. self.assertEqual(3, f.call_count)
  328. class TestExternalNetwork(Ml2PluginV2TestCase):
  329. def _create_external_network(self):
  330. data = {'network': {'name': 'net1',
  331. 'router:external': 'True',
  332. 'tenant_id': 'tenant_one'}}
  333. network_req = self.new_create_request('networks', data)
  334. network = self.deserialize(self.fmt,
  335. network_req.get_response(self.api))
  336. return network
  337. def test_external_network_type_none(self):
  338. cfg.CONF.set_default('external_network_type',
  339. None,
  340. group='ml2')
  341. network = self._create_external_network()
  342. # For external network, expected network type to be
  343. # tenant_network_types which is by default 'local'.
  344. self.assertEqual(constants.TYPE_LOCAL,
  345. network['network'][pnet.NETWORK_TYPE])
  346. # No physical network specified, expected 'None'.
  347. self.assertIsNone(network['network'][pnet.PHYSICAL_NETWORK])
  348. # External network will not have a segmentation id.
  349. self.assertIsNone(network['network'][pnet.SEGMENTATION_ID])
  350. # External network will not have multiple segments.
  351. self.assertNotIn(mpnet.SEGMENTS, network['network'])
  352. def test_external_network_type_vlan(self):
  353. cfg.CONF.set_default('external_network_type',
  354. constants.TYPE_VLAN,
  355. group='ml2')
  356. network = self._create_external_network()
  357. # For external network, expected network type to be 'vlan'.
  358. self.assertEqual(constants.TYPE_VLAN,
  359. network['network'][pnet.NETWORK_TYPE])
  360. # Physical network is expected.
  361. self.assertIsNotNone(network['network'][pnet.PHYSICAL_NETWORK])
  362. # External network will have a segmentation id.
  363. self.assertIsNotNone(network['network'][pnet.SEGMENTATION_ID])
  364. # External network will not have multiple segments.
  365. self.assertNotIn(mpnet.SEGMENTS, network['network'])
  366. class TestMl2NetworksWithVlanTransparencyBase(TestMl2NetworksV2):
  367. data = {'network': {'name': 'net1',
  368. mpnet.SEGMENTS:
  369. [{pnet.NETWORK_TYPE: 'vlan',
  370. pnet.PHYSICAL_NETWORK: 'physnet1'}],
  371. 'tenant_id': 'tenant_one',
  372. 'vlan_transparent': 'True'}}
  373. def setUp(self, plugin=None):
  374. cfg.CONF.set_override('vlan_transparent', True)
  375. super(TestMl2NetworksWithVlanTransparencyBase, self).setUp(plugin)
  376. class TestMl2NetworksWithVlanTransparency(
  377. TestMl2NetworksWithVlanTransparencyBase):
  378. _mechanism_drivers = ['test']
  379. def test_create_network_vlan_transparent_fail(self):
  380. with mock.patch.object(mech_test.TestMechanismDriver,
  381. 'check_vlan_transparency',
  382. return_value=False):
  383. network_req = self.new_create_request('networks', self.data)
  384. res = network_req.get_response(self.api)
  385. self.assertEqual(500, res.status_int)
  386. error_result = self.deserialize(self.fmt, res)['NeutronError']
  387. self.assertEqual("VlanTransparencyDriverError",
  388. error_result['type'])
  389. def test_create_network_vlan_transparent(self):
  390. with mock.patch.object(mech_test.TestMechanismDriver,
  391. 'check_vlan_transparency',
  392. return_value=True):
  393. network_req = self.new_create_request('networks', self.data)
  394. res = network_req.get_response(self.api)
  395. self.assertEqual(201, res.status_int)
  396. network = self.deserialize(self.fmt, res)['network']
  397. self.assertIn('vlan_transparent', network)
  398. class TestMl2NetworksWithVlanTransparencyAndMTU(
  399. TestMl2NetworksWithVlanTransparencyBase):
  400. _mechanism_drivers = ['test']
  401. def test_create_network_vlan_transparent_and_mtu(self):
  402. with mock.patch.object(mech_test.TestMechanismDriver,
  403. 'check_vlan_transparency',
  404. return_value=True):
  405. cfg.CONF.set_override('path_mtu', 1000, group='ml2')
  406. cfg.CONF.set_override('global_physnet_mtu', 1000)
  407. network_req = self.new_create_request('networks', self.data)
  408. res = network_req.get_response(self.api)
  409. self.assertEqual(201, res.status_int)
  410. network = self.deserialize(self.fmt, res)['network']
  411. self.assertEqual(1000, network['mtu'])
  412. self.assertIn('vlan_transparent', network)
  413. self.assertTrue(network['vlan_transparent'])
  414. self.assertTrue(network['vlan_transparent'])
  415. class TestMl2NetworksWithAvailabilityZone(TestMl2NetworksV2):
  416. def test_create_network_availability_zone(self):
  417. az_hints = ['az1', 'az2']
  418. data = {'network': {'name': 'net1',
  419. az_def.AZ_HINTS: az_hints,
  420. 'tenant_id': 'tenant_one'}}
  421. with mock.patch.object(agents_db.AgentAvailabilityZoneMixin,
  422. 'validate_availability_zones'):
  423. network_req = self.new_create_request('networks', data)
  424. res = network_req.get_response(self.api)
  425. self.assertEqual(201, res.status_int)
  426. network = self.deserialize(self.fmt, res)['network']
  427. self.assertEqual(az_hints, network[az_def.AZ_HINTS])
  428. class TestMl2SubnetsV2(test_plugin.TestSubnetsV2,
  429. Ml2PluginV2TestCase):
  430. def test_subnet_after_create_callback(self):
  431. after_create = mock.Mock()
  432. registry.subscribe(after_create, resources.SUBNET, events.AFTER_CREATE)
  433. with self.subnet() as s:
  434. after_create.assert_called_once_with(
  435. resources.SUBNET, events.AFTER_CREATE, mock.ANY,
  436. context=mock.ANY, subnet=mock.ANY)
  437. kwargs = after_create.mock_calls[0][2]
  438. self.assertEqual(s['subnet']['id'], kwargs['subnet']['id'])
  439. def test_port_update_subnetnotfound(self):
  440. with self.network() as n:
  441. with self.subnet(network=n, cidr='1.1.1.0/24') as s1,\
  442. self.subnet(network=n, cidr='1.1.2.0/24') as s2,\
  443. self.subnet(network=n, cidr='1.1.3.0/24') as s3:
  444. fixed_ips = [{'subnet_id': s1['subnet']['id']},
  445. {'subnet_id': s2['subnet']['id']},
  446. {'subnet_id': s3['subnet']['id']}]
  447. with self.port(subnet=s1, fixed_ips=fixed_ips,
  448. device_owner=constants.DEVICE_OWNER_DHCP) as p:
  449. plugin = directory.get_plugin()
  450. orig_update = plugin.update_port
  451. def delete_before_update(ctx, *args, **kwargs):
  452. # swap back out with original so only called once
  453. plugin.update_port = orig_update
  454. # delete s2 in the middle of s1 port_update
  455. plugin.delete_subnet(ctx, s2['subnet']['id'])
  456. return plugin.update_port(ctx, *args, **kwargs)
  457. plugin.update_port = delete_before_update
  458. req = self.new_delete_request('subnets',
  459. s1['subnet']['id'])
  460. res = req.get_response(self.api)
  461. self.assertEqual(204, res.status_int)
  462. # ensure port only has 1 IP on s3
  463. port = self._show('ports', p['port']['id'])['port']
  464. self.assertEqual(1, len(port['fixed_ips']))
  465. self.assertEqual(s3['subnet']['id'],
  466. port['fixed_ips'][0]['subnet_id'])
  467. def test_subnet_after_update_callback(self):
  468. after_update = mock.Mock()
  469. registry.subscribe(after_update, resources.SUBNET, events.AFTER_UPDATE)
  470. with self.subnet() as s:
  471. data = {'subnet': {'name': 'updated'}}
  472. req = self.new_update_request('subnets', data, s['subnet']['id'])
  473. self.deserialize(self.fmt, req.get_response(self.api))
  474. after_update.assert_called_once_with(
  475. resources.SUBNET, events.AFTER_UPDATE, mock.ANY,
  476. context=mock.ANY, subnet=mock.ANY,
  477. original_subnet=mock.ANY)
  478. kwargs = after_update.mock_calls[0][2]
  479. self.assertEqual(s['subnet']['name'],
  480. kwargs['original_subnet']['name'])
  481. self.assertEqual('updated', kwargs['subnet']['name'])
  482. def test_subnet_after_delete_callback(self):
  483. after_delete = mock.Mock()
  484. registry.subscribe(after_delete, resources.SUBNET, events.AFTER_DELETE)
  485. with self.subnet() as s:
  486. req = self.new_delete_request('subnets', s['subnet']['id'])
  487. req.get_response(self.api)
  488. after_delete.assert_called_once_with(
  489. resources.SUBNET, events.AFTER_DELETE, mock.ANY,
  490. context=mock.ANY, subnet=mock.ANY)
  491. kwargs = after_delete.mock_calls[0][2]
  492. self.assertEqual(s['subnet']['id'], kwargs['subnet']['id'])
  493. def test_delete_subnet_race_with_dhcp_port_creation(self):
  494. with self.network() as network:
  495. with self.subnet(network=network) as subnet:
  496. subnet_id = subnet['subnet']['id']
  497. attempt = [0]
  498. def create_dhcp_port(*args, **kwargs):
  499. """A method to emulate race condition.
  500. Adds dhcp port in the middle of subnet delete
  501. """
  502. if attempt[0] > 0:
  503. return False
  504. attempt[0] += 1
  505. data = {'port': {'network_id': network['network']['id'],
  506. 'tenant_id':
  507. network['network']['tenant_id'],
  508. 'name': 'port1',
  509. 'admin_state_up': 1,
  510. 'device_id': '',
  511. 'device_owner':
  512. constants.DEVICE_OWNER_DHCP,
  513. 'fixed_ips': [{'subnet_id': subnet_id}]}}
  514. plugin = directory.get_plugin()
  515. plugin.create_port(context.get_admin_context(), data)
  516. # we mock _subnet_check_ip_allocations with method
  517. # that creates DHCP port 'in the middle' of subnet_delete
  518. # causing retry this way subnet is deleted on the
  519. # second attempt
  520. registry.subscribe(create_dhcp_port, resources.SUBNET,
  521. events.PRECOMMIT_DELETE)
  522. req = self.new_delete_request('subnets', subnet_id)
  523. res = req.get_response(self.api)
  524. self.assertEqual(204, res.status_int)
  525. self.assertEqual(1, attempt[0])
  526. def test_create_subnet_check_mtu_in_mech_context(self):
  527. plugin = directory.get_plugin()
  528. plugin.mechanism_manager.create_subnet_precommit = mock.Mock()
  529. net_arg = {pnet.NETWORK_TYPE: 'vxlan',
  530. pnet.SEGMENTATION_ID: '1'}
  531. network = self._make_network(self.fmt, 'net1', True,
  532. arg_list=(pnet.NETWORK_TYPE,
  533. pnet.SEGMENTATION_ID,),
  534. **net_arg)
  535. with self.subnet(network=network):
  536. mock_subnet_pre = plugin.mechanism_manager.create_subnet_precommit
  537. observerd_mech_context = mock_subnet_pre.call_args_list[0][0][0]
  538. self.assertEqual(network['network']['mtu'],
  539. observerd_mech_context.network.current['mtu'])
  540. class TestMl2DbOperationBounds(test_plugin.DbOperationBoundMixin,
  541. Ml2PluginV2TestCase):
  542. """Test cases to assert constant query count for list operations.
  543. These test cases assert that an increase in the number of objects
  544. does not result in an increase of the number of db operations. All
  545. database lookups during a list operation should be performed in bulk
  546. so the number of queries required for 2 objects instead of 1 should
  547. stay the same.
  548. """
  549. def setUp(self):
  550. super(TestMl2DbOperationBounds, self).setUp()
  551. self.kwargs = self.get_api_kwargs()
  552. def make_network(self):
  553. return self._make_network(self.fmt, 'name', True, **self.kwargs)
  554. def make_subnet(self):
  555. net = self.make_network()
  556. setattr(self, '_subnet_count', getattr(self, '_subnet_count', 0) + 1)
  557. cidr = '1.%s.0.0/24' % self._subnet_count
  558. return self._make_subnet(self.fmt, net, None, cidr, **self.kwargs)
  559. def make_port(self):
  560. net = self.make_network()
  561. return self._make_port(self.fmt, net['network']['id'], **self.kwargs)
  562. def test_network_list_queries_constant(self):
  563. self._assert_object_list_queries_constant(self.make_network,
  564. 'networks')
  565. def test_subnet_list_queries_constant(self):
  566. self._assert_object_list_queries_constant(self.make_subnet, 'subnets')
  567. def test_port_list_queries_constant(self):
  568. self._assert_object_list_queries_constant(self.make_port, 'ports')
  569. self._assert_object_list_queries_constant(self.make_port, 'ports',
  570. filters=['device_id'])
  571. self._assert_object_list_queries_constant(self.make_port, 'ports',
  572. filters=['device_id',
  573. 'device_owner'])
  574. self._assert_object_list_queries_constant(self.make_port, 'ports',
  575. filters=['tenant_id',
  576. 'name',
  577. 'device_id'])
  578. class TestMl2DbOperationBoundsTenant(TestMl2DbOperationBounds):
  579. admin = False
  580. class TestMl2DbOperationBoundsTenantRbac(TestMl2DbOperationBoundsTenant):
  581. def make_port_in_shared_network(self):
  582. context_ = self._get_context()
  583. # create shared network owned by the tenant; we use direct driver call
  584. # because default policy does not allow users to create shared networks
  585. net = self.driver.create_network(
  586. context.get_admin_context(),
  587. {'network': {'name': 'net1',
  588. 'tenant_id': context_.tenant,
  589. 'admin_state_up': True,
  590. 'shared': True}})
  591. # create port that belongs to another tenant
  592. return self._make_port(
  593. self.fmt, net['id'],
  594. set_context=True, tenant_id='fake_tenant')
  595. def test_port_list_in_shared_network_queries_constant(self):
  596. self._assert_object_list_queries_constant(
  597. self.make_port_in_shared_network, 'ports')
  598. class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
  599. def test__port_provisioned_with_blocks(self):
  600. plugin = directory.get_plugin()
  601. ups = mock.patch.object(plugin, 'update_port_status').start()
  602. with self.port() as port:
  603. mock.patch('neutron.plugins.ml2.plugin.db.get_port').start()
  604. provisioning_blocks.add_provisioning_component(
  605. self.context, port['port']['id'], 'port', 'DHCP')
  606. plugin._port_provisioned('port', 'evt', 'trigger',
  607. self.context, port['port']['id'])
  608. self.assertFalse(ups.called)
  609. def test__port_provisioned_no_binding(self):
  610. plugin = directory.get_plugin()
  611. with self.network() as net:
  612. net_id = net['network']['id']
  613. port_id = 'fake_id'
  614. port_db = models_v2.Port(
  615. id=port_id, tenant_id='tenant', network_id=net_id,
  616. mac_address='08:00:01:02:03:04', admin_state_up=True,
  617. status='ACTIVE', device_id='vm_id',
  618. device_owner=DEVICE_OWNER_COMPUTE
  619. )
  620. with db_api.context_manager.writer.using(self.context):
  621. self.context.session.add(port_db)
  622. self.assertIsNone(plugin._port_provisioned('port', 'evt', 'trigger',
  623. self.context, port_id))
  624. def test_port_after_create_outside_transaction(self):
  625. self.tx_open = True
  626. receive = lambda *a, **k: setattr(self, 'tx_open',
  627. k['context'].session.is_active)
  628. registry.subscribe(receive, resources.PORT, events.AFTER_CREATE)
  629. with self.port():
  630. self.assertFalse(self.tx_open)
  631. def test_port_after_update_outside_transaction(self):
  632. self.tx_open = True
  633. receive = lambda *a, **k: setattr(self, 'tx_open',
  634. k['context'].session.is_active)
  635. with self.port() as p:
  636. registry.subscribe(receive, resources.PORT, events.AFTER_UPDATE)
  637. self._update('ports', p['port']['id'],
  638. {'port': {'name': 'update'}})
  639. self.assertFalse(self.tx_open)
  640. def test_port_after_delete_outside_transaction(self):
  641. self.tx_open = True
  642. receive = lambda *a, **k: setattr(self, 'tx_open',
  643. k['context'].session.is_active)
  644. with self.port() as p:
  645. registry.subscribe(receive, resources.PORT, events.AFTER_DELETE)
  646. self._delete('ports', p['port']['id'])
  647. self.assertFalse(self.tx_open)
  648. def test_bulk_ports_before_and_after_events_outside_of_txn(self):
  649. with self.network() as n:
  650. pass
  651. # capture session states during each before and after event
  652. before = []
  653. after = []
  654. b_func = lambda *a, **k: before.append(k['context'].session.is_active)
  655. a_func = lambda *a, **k: after.append(k['context'].session.is_active)
  656. registry.subscribe(b_func, resources.PORT, events.BEFORE_CREATE)
  657. registry.subscribe(a_func, resources.PORT, events.AFTER_CREATE)
  658. data = [{'tenant_id': self._tenant_id,
  659. 'network_id': n['network']['id']}] * 4
  660. self._create_bulk_from_list(
  661. self.fmt, 'port', data, context=context.get_admin_context())
  662. # ensure events captured
  663. self.assertTrue(before)
  664. self.assertTrue(after)
  665. # ensure session was closed for all
  666. self.assertFalse(any(before))
  667. self.assertFalse(any(after))
  668. def test_create_router_port_and_fail_create_postcommit(self):
  669. with mock.patch.object(managers.MechanismManager,
  670. 'create_port_postcommit',
  671. side_effect=ml2_exc.MechanismDriverError(
  672. method='create_port_postcommit')):
  673. l3_plugin = directory.get_plugin(plugin_constants.L3)
  674. data = {'router': {'name': 'router', 'admin_state_up': True,
  675. 'tenant_id': 'fake_tenant'}}
  676. r = l3_plugin.create_router(self.context, data)
  677. with self.subnet() as s:
  678. data = {'subnet_id': s['subnet']['id']}
  679. self.assertRaises(ml2_exc.MechanismDriverError,
  680. l3_plugin.add_router_interface,
  681. self.context, r['id'], data)
  682. res_ports = self._list('ports')['ports']
  683. self.assertEqual([], res_ports)
  684. def test_create_router_port_and_fail_bind_port_if_needed(self):
  685. with mock.patch.object(ml2_plugin.Ml2Plugin, '_bind_port_if_needed',
  686. side_effect=ml2_exc.MechanismDriverError(
  687. method='_bind_port_if_needed')):
  688. l3_plugin = directory.get_plugin(plugin_constants.L3)
  689. data = {'router': {'name': 'router', 'admin_state_up': True,
  690. 'tenant_id': 'fake_tenant'}}
  691. r = l3_plugin.create_router(self.context, data)
  692. with self.subnet() as s:
  693. data = {'subnet_id': s['subnet']['id']}
  694. self.assertRaises(ml2_exc.MechanismDriverError,
  695. l3_plugin.add_router_interface,
  696. self.context, r['id'], data)
  697. res_ports = self._list('ports')['ports']
  698. self.assertEqual([], res_ports)
  699. def test_update_port_status_build(self):
  700. with self.port() as port:
  701. self.assertEqual('DOWN', port['port']['status'])
  702. self.assertEqual('DOWN', self.port_create_status)
  703. def test_notify_port_updated_for_status_change(self):
  704. ctx = context.get_admin_context()
  705. plugin = directory.get_plugin()
  706. with self.port() as port:
  707. with mock.patch.object(self.plugin,
  708. '_notify_port_updated') as notify_mock:
  709. port['port']['status'] = constants.PORT_STATUS_ACTIVE
  710. plugin.update_port(ctx, port['port']['id'], port)
  711. self.assertTrue(notify_mock.called)
  712. def test_update_port_status_short_id(self):
  713. ctx = context.get_admin_context()
  714. plugin = directory.get_plugin()
  715. with self.port() as port:
  716. with mock.patch.object(ml2_db, 'get_binding_levels',
  717. return_value=[]) as mock_gbl:
  718. port_id = port['port']['id']
  719. short_id = port_id[:11]
  720. plugin.update_port_status(ctx, short_id, 'UP')
  721. mock_gbl.assert_called_once_with(mock.ANY, port_id, mock.ANY)
  722. def _add_fake_dhcp_agent(self):
  723. agent = mock.Mock()
  724. plugin = directory.get_plugin()
  725. self.get_dhcp_mock = mock.patch.object(
  726. plugin, 'get_dhcp_agents_hosting_networks',
  727. return_value=[agent]).start()
  728. def test_dhcp_provisioning_blocks_inserted_on_create_with_agents(self):
  729. self._add_fake_dhcp_agent()
  730. with mock.patch.object(provisioning_blocks,
  731. 'add_provisioning_component') as ap:
  732. with self.port():
  733. self.assertTrue(ap.called)
  734. def test_dhcp_provisioning_blocks_skipped_on_create_with_no_dhcp(self):
  735. self._add_fake_dhcp_agent()
  736. with self.subnet(enable_dhcp=False) as subnet:
  737. with mock.patch.object(provisioning_blocks,
  738. 'add_provisioning_component') as ap:
  739. with self.port(subnet=subnet):
  740. self.assertFalse(ap.called)
  741. def _test_dhcp_provisioning_blocks_inserted_on_update(self, update_dict,
  742. expected_block):
  743. ctx = context.get_admin_context()
  744. plugin = directory.get_plugin()
  745. self._add_fake_dhcp_agent()
  746. with self.port() as port:
  747. with mock.patch.object(provisioning_blocks,
  748. 'add_provisioning_component') as ap:
  749. port['port'].update(update_dict)
  750. plugin.update_port(ctx, port['port']['id'], port)
  751. self.assertEqual(expected_block, ap.called)
  752. def test_dhcp_provisioning_blocks_not_inserted_on_no_addr_change(self):
  753. update = {'binding:host_id': 'newhost'}
  754. self._test_dhcp_provisioning_blocks_inserted_on_update(update, False)
  755. def test_dhcp_provisioning_blocks_inserted_on_addr_change(self):
  756. update = {'binding:host_id': 'newhost',
  757. 'mac_address': '11:22:33:44:55:66'}
  758. self._test_dhcp_provisioning_blocks_inserted_on_update(update, True)
  759. def test_dhcp_provisioning_blocks_removed_without_dhcp_agents(self):
  760. with mock.patch.object(provisioning_blocks,
  761. 'remove_provisioning_component') as cp:
  762. with self.port():
  763. self.assertTrue(cp.called)
  764. def test_create_update_get_port_same_fixed_ips_order(self):
  765. ctx = context.get_admin_context()
  766. plugin = directory.get_plugin()
  767. initial_fixed_ips = [{'ip_address': '10.0.0.5'},
  768. {'ip_address': '10.0.0.7'},
  769. {'ip_address': '10.0.0.6'}]
  770. with self.port(fixed_ips=initial_fixed_ips) as port:
  771. show = plugin.get_port(ctx, port['port']['id'])
  772. self.assertEqual(port['port']['fixed_ips'], show['fixed_ips'])
  773. new_fixed_ips = list(reversed(initial_fixed_ips))
  774. port['port']['fixed_ips'] = new_fixed_ips
  775. updated = plugin.update_port(ctx, port['port']['id'], port)
  776. self.assertEqual(show['fixed_ips'], updated['fixed_ips'])
  777. updated = plugin.get_port(ctx, port['port']['id'])
  778. self.assertEqual(show['fixed_ips'], updated['fixed_ips'])
  779. def test_update_port_fixed_ip_changed(self):
  780. ctx = context.get_admin_context()
  781. plugin = directory.get_plugin()
  782. fixed_ip_data = [{'ip_address': '10.0.0.4'}]
  783. with self.port(fixed_ips=fixed_ip_data) as port,\
  784. mock.patch.object(
  785. plugin.notifier,
  786. 'security_groups_member_updated') as sg_member_update:
  787. port['port']['fixed_ips'][0]['ip_address'] = '10.0.0.3'
  788. plugin.update_port(ctx, port['port']['id'], port)
  789. self.assertTrue(sg_member_update.called)
  790. def test_update_port_status_with_network(self):
  791. registry.clear() # don't care about callback behavior
  792. ctx = context.get_admin_context()
  793. plugin = directory.get_plugin()
  794. with self.port() as port:
  795. net = plugin.get_network(ctx, port['port']['network_id'])
  796. with mock.patch.object(plugin, 'get_networks') as get_nets:
  797. plugin.update_port_status(ctx, port['port']['id'], 'UP',
  798. network=net)
  799. self.assertFalse(get_nets.called)
  800. def test_update_port_mac(self):
  801. self.check_update_port_mac(
  802. host_arg={portbindings.HOST_ID: HOST},
  803. arg_list=(portbindings.HOST_ID,))
  804. def test_update_non_existent_port(self):
  805. ctx = context.get_admin_context()
  806. plugin = directory.get_plugin()
  807. data = {'port': {'admin_state_up': False}}
  808. self.assertRaises(exc.PortNotFound, plugin.update_port, ctx,
  809. 'invalid-uuid', data)
  810. def test_delete_non_existent_port(self):
  811. ctx = context.get_admin_context()
  812. plugin = directory.get_plugin()
  813. with mock.patch.object(ml2_plugin.LOG, 'debug') as log_debug:
  814. plugin.delete_port(ctx, 'invalid-uuid', l3_port_check=False)
  815. log_debug.assert_has_calls([
  816. mock.call(_("Deleting port %s"), 'invalid-uuid'),
  817. mock.call(_("The port '%s' was deleted"), 'invalid-uuid')
  818. ])
  819. def test_l3_cleanup_on_net_delete(self):
  820. l3plugin = directory.get_plugin(plugin_constants.L3)
  821. kwargs = {'arg_list': (extnet_apidef.EXTERNAL,),
  822. extnet_apidef.EXTERNAL: True}
  823. with self.network(**kwargs) as n:
  824. with self.subnet(network=n, cidr='200.0.0.0/22'):
  825. l3plugin.create_floatingip(
  826. context.get_admin_context(),
  827. {'floatingip': {'floating_network_id': n['network']['id'],
  828. 'tenant_id': n['network']['tenant_id'],
  829. 'dns_name': '', 'dns_domain': ''}}
  830. )
  831. self._delete('networks', n['network']['id'])
  832. flips = l3plugin.get_floatingips(context.get_admin_context())
  833. self.assertFalse(flips)
  834. def test_create_ports_bulk_port_binding_failure(self):
  835. ctx = context.get_admin_context()
  836. with self.network() as net:
  837. plugin = directory.get_plugin()
  838. with mock.patch.object(plugin, '_bind_port_if_needed',
  839. side_effect=ml2_exc.MechanismDriverError(
  840. method='create_port_bulk')) as _bind_port_if_needed:
  841. res = self._create_port_bulk(self.fmt, 2, net['network']['id'],
  842. 'test', True, context=ctx)
  843. self.assertTrue(_bind_port_if_needed.called)
  844. # We expect a 500 as we injected a fault in the plugin
  845. self._validate_behavior_on_bulk_failure(
  846. res, 'ports', webob.exc.HTTPServerError.code)
  847. def test_create_ports_bulk_with_sec_grp(self):
  848. ctx = context.get_admin_context()
  849. plugin = directory.get_plugin()
  850. with self.network() as net,\
  851. mock.patch.object(plugin.notifier,
  852. 'security_groups_member_updated') as m_upd:
  853. res = self._create_port_bulk(self.fmt, 3, net['network']['id'],
  854. 'test', True, context=ctx)
  855. ports = self.deserialize(self.fmt, res)
  856. used_sg = ports['ports'][0]['security_groups']
  857. m_upd.assert_has_calls(
  858. [mock.call(ctx, [sg]) for sg in used_sg], any_order=True)
  859. def test_create_ports_bulk_with_sec_grp_member_provider_update(self):
  860. ctx = context.get_admin_context()
  861. plugin = directory.get_plugin()
  862. with self.network() as net,\
  863. mock.patch.object(plugin.notifier,
  864. 'security_groups_member_updated') as m_upd:
  865. net_id = net['network']['id']
  866. data = [{
  867. 'network_id': net_id,
  868. 'tenant_id': self._tenant_id
  869. },
  870. {
  871. 'network_id': net_id,
  872. 'tenant_id': self._tenant_id,
  873. 'device_owner': constants.DEVICE_OWNER_DHCP
  874. }
  875. ]
  876. res = self._create_bulk_from_list(self.fmt, 'port',
  877. data, context=ctx)
  878. ports = self.deserialize(self.fmt, res)
  879. used_sg = ports['ports'][0]['security_groups']
  880. m_upd.assert_called_once_with(ctx, used_sg)
  881. m_upd.reset_mock()
  882. data[0]['device_owner'] = constants.DEVICE_OWNER_DHCP
  883. self._create_bulk_from_list(self.fmt, 'port',
  884. data, context=ctx)
  885. self.assertFalse(m_upd.called)
  886. def test_create_ports_bulk_with_sec_grp_provider_update_ipv6(self):
  887. ctx = context.get_admin_context()
  888. plugin = directory.get_plugin()
  889. fake_prefix = '2001:db8::/64'
  890. fake_gateway = 'fe80::1'
  891. with self.network() as net:
  892. with self.subnet(net,
  893. gateway_ip=fake_gateway,
  894. cidr=fake_prefix,
  895. ip_version=6) as snet_v6,\
  896. mock.patch.object(
  897. plugin.notifier,
  898. 'security_groups_member_updated') as m_upd:
  899. net_id = net['network']['id']
  900. data = [{
  901. 'network_id': net_id,
  902. 'tenant_id': self._tenant_id,
  903. 'fixed_ips': [{'subnet_id': snet_v6['subnet']['id']}],
  904. 'device_owner': constants.DEVICE_OWNER_ROUTER_INTF
  905. }
  906. ]
  907. self._create_bulk_from_list(self.fmt, 'port',
  908. data, context=ctx)
  909. self.assertFalse(m_upd.called)
  910. def test_delete_port_no_notify_in_disassociate_floatingips(self):
  911. ctx = context.get_admin_context()
  912. plugin = directory.get_plugin()
  913. l3plugin = directory.get_plugin(plugin_constants.L3)
  914. with self.port() as port,\
  915. mock.patch.object(
  916. l3plugin,
  917. 'disassociate_floatingips') as disassociate_floatingips,\
  918. mock.patch.object(registry, 'notify') as notify:
  919. port_id = port['port']['id']
  920. plugin.delete_port(ctx, port_id)
  921. # check that no notification was requested while under
  922. # transaction
  923. disassociate_floatingips.assert_has_calls([
  924. mock.call(ctx, port_id, do_notify=False)
  925. ])
  926. # check that notifier was still triggered
  927. self.assertTrue(notify.call_counts)
  928. def test_registry_notify_before_after_port_binding(self):
  929. plugin = directory.get_plugin()
  930. ctx = context.get_admin_context()
  931. b_update_events = []
  932. a_update_events = []
  933. b_receiver = lambda *a, **k: b_update_events.append(k)
  934. a_receiver = lambda *a, **k: a_update_events.append(k['port'])
  935. registry.subscribe(b_receiver, resources.PORT,
  936. events.BEFORE_UPDATE)
  937. registry.subscribe(a_receiver, resources.PORT,
  938. events.AFTER_UPDATE)
  939. with self.port() as p:
  940. port = {'port': {'binding:host_id': 'newhost'}}
  941. plugin.update_port(ctx, p['port']['id'], port)
  942. # updating in the host should result in two AFTER_UPDATE events.
  943. # one to change the host_id, the second to commit a binding
  944. self.assertEqual(2, len(b_update_events))
  945. self.assertEqual({'context': ctx,
  946. 'port': {'binding:host_id': 'newhost'},
  947. 'original_port': mock.ANY},
  948. b_update_events[0])
  949. self.assertIn('orig_binding', b_update_events[1])
  950. self.assertIn('new_binding', b_update_events[1])
  951. self.assertDictContainsSubset({'context': ctx}, b_update_events[1])
  952. self.assertDictContainsSubset({
  953. 'admin_state_up': True,
  954. 'binding:host_id': 'newhost',
  955. 'binding:vif_type': 'unbound',
  956. 'binding:vnic_type': u'normal',
  957. 'status': 'DOWN'},
  958. b_update_events[1]['port'])
  959. self.assertEqual('newhost', a_update_events[0]['binding:host_id'])
  960. self.assertEqual('unbound', a_update_events[0]['binding:vif_type'])
  961. self.assertEqual('newhost', a_update_events[1]['binding:host_id'])
  962. self.assertNotEqual('unbound', a_update_events[1]['binding:vif_type'])
  963. def test_check_if_compute_port_serviced_by_dvr(self):
  964. self.assertTrue(utils.is_dvr_serviced(DEVICE_OWNER_COMPUTE))
  965. def test_check_if_lbaas_vip_port_serviced_by_dvr(self):
  966. self.assertTrue(utils.is_dvr_serviced(
  967. constants.DEVICE_OWNER_LOADBALANCER))
  968. def test_check_if_lbaasv2_vip_port_serviced_by_dvr(self):
  969. self.assertTrue(utils.is_dvr_serviced(
  970. constants.DEVICE_OWNER_LOADBALANCERV2))
  971. def test_check_if_dhcp_port_serviced_by_dvr(self):
  972. self.assertTrue(utils.is_dvr_serviced(constants.DEVICE_OWNER_DHCP))
  973. def test_check_if_port_not_serviced_by_dvr(self):
  974. self.assertFalse(utils.is_dvr_serviced(
  975. constants.DEVICE_OWNER_ROUTER_INTF))
  976. def test_disassociate_floatingips_do_notify_returns_nothing(self):
  977. ctx = context.get_admin_context()
  978. l3plugin = directory.get_plugin(plugin_constants.L3)
  979. with self.port() as port:
  980. port_id = port['port']['id']
  981. # check that nothing is returned when notifications are handled
  982. # by the called method
  983. self.assertIsNone(l3plugin.disassociate_floatingips(ctx, port_id))
  984. def test_create_port_tolerates_db_deadlock(self):
  985. plugin = directory.get_plugin()
  986. with self.network() as net:
  987. with self.subnet(network=net) as subnet:
  988. _orig = plugin._get_port
  989. self._failed = False
  990. def fail_once(*args, **kwargs):
  991. if not self._failed:
  992. self._failed = True
  993. raise db_exc.DBDeadlock()
  994. return _orig(*args, **kwargs)
  995. with mock.patch.object(plugin, '_get_port',
  996. side_effect=fail_once) as get_port_mock:
  997. port_kwargs = {portbindings.HOST_ID: 'host1',
  998. 'subnet': subnet,
  999. 'device_id': 'deadlocktest'}
  1000. with self.port(arg_list=(portbindings.HOST_ID,),
  1001. **port_kwargs) as port:
  1002. self.assertTrue(port['port']['id'])
  1003. self.assertTrue(get_port_mock.called)
  1004. # make sure that we didn't create more than one port on
  1005. # the retry
  1006. query_params = "network_id=%s" % net['network']['id']
  1007. query_params += "&device_id=%s" % 'deadlocktest'
  1008. ports = self._list('ports', query_params=query_params)
  1009. self.assertEqual(1, len(ports['ports']))
  1010. def test_delete_port_tolerates_db_deadlock(self):
  1011. ctx = context.get_admin_context()
  1012. plugin = directory.get_plugin()
  1013. with self.port() as port:
  1014. port_db = plugin._get_port(ctx, port['port']['id'])
  1015. with mock.patch.object(plugin, '_get_port') as gp:
  1016. gp.side_effect = [db_exc.DBDeadlock] + [port_db] * 3
  1017. req = self.new_delete_request('ports', port['port']['id'])
  1018. res = req.get_response(self.api)
  1019. self.assertEqual(204, res.status_int)
  1020. self.assertGreater(gp.call_count, 1)
  1021. self.assertRaises(
  1022. exc.PortNotFound, plugin.get_port, ctx, port['port']['id'])
  1023. def test_port_create_resillient_to_duplicate_records(self):
  1024. def make_port():
  1025. with self.port():
  1026. pass
  1027. self._test_operation_resillient_to_ipallocation_failure(make_port)
  1028. def test_port_update_resillient_to_duplicate_records(self):
  1029. cidr = '10.0.0.0/24'
  1030. allocation_pools = [{'start': '10.0.0.2', 'end': '10.0.0.8'}]
  1031. with self.subnet(cidr=cidr,
  1032. allocation_pools=allocation_pools) as subnet:
  1033. with self.port(subnet=subnet) as p:
  1034. data = {'port': {'fixed_ips': [{'ip_address': '10.0.0.9'}]}}
  1035. req = self.new_update_request('ports', data, p['port']['id'])
  1036. def do_request():
  1037. self.assertEqual(200,
  1038. req.get_response(self.api).status_int)
  1039. self._test_operation_resillient_to_ipallocation_failure(
  1040. do_request)
  1041. def _test_operation_resillient_to_ipallocation_failure(self, func):
  1042. class IPAllocationsGrenade(object):
  1043. insert_ip_called = False
  1044. except_raised = False
  1045. def execute(self, con, curs, stmt, *args, **kwargs):
  1046. if 'INSERT INTO ipallocations' in stmt:
  1047. self.insert_ip_called = True
  1048. def commit(self, con):
  1049. # we blow up on commit to simulate another thread/server
  1050. # stealing our IP before our transaction was done
  1051. if self.insert_ip_called and not self.except_raised:
  1052. self.except_raised = True
  1053. raise db_exc.DBDuplicateEntry()
  1054. listener = IPAllocationsGrenade()
  1055. engine = db_api.context_manager.writer.get_engine()
  1056. db_api.sqla_listen(engine, 'before_cursor_execute', listener.execute)
  1057. db_api.sqla_listen(engine, 'commit', listener.commit)
  1058. func()
  1059. # make sure that the grenade went off during the commit
  1060. self.assertTrue(listener.except_raised)
  1061. def test_list_ports_filtered_by_fixed_ip_substring(self):
  1062. # for this test we need to enable overlapping ips
  1063. cfg.CONF.set_default('allow_overlapping_ips', True)
  1064. with self.port() as port1, self.port():
  1065. fixed_ips = port1['port']['fixed_ips'][0]
  1066. query_params = """
  1067. fixed_ips=ip_address_substr%%3D%s&fixed_ips=subnet_id%%3D%s
  1068. """.strip() % (fixed_ips['ip_address'][:-1],
  1069. fixed_ips['subnet_id'])
  1070. self._test_list_resources('port', [port1],
  1071. query_params=query_params)
  1072. query_params = """
  1073. fixed_ips=ip_address_substr%%3D%s&fixed_ips=subnet_id%%3D%s
  1074. """.strip() % (fixed_ips['ip_address'][1:],
  1075. fixed_ips['subnet_id'])
  1076. self._test_list_resources('port', [port1],
  1077. query_params=query_params)
  1078. query_params = """
  1079. fixed_ips=ip_address_substr%%3D%s&fixed_ips=subnet_id%%3D%s
  1080. """.strip() % ('192.168.',
  1081. fixed_ips['subnet_id'])
  1082. self._test_list_resources('port', [],
  1083. query_params=query_params)
  1084. def test_list_ports_filtered_by_fixed_ip_substring_dual_stack(self):
  1085. with self.subnet() as subnet:
  1086. # Get a IPv4 and IPv6 address
  1087. tenant_id = subnet['subnet']['tenant_id']
  1088. net_id = subnet['subnet']['network_id']
  1089. res = self._create_subnet(
  1090. self.fmt,
  1091. tenant_id=tenant_id,
  1092. net_id=net_id,
  1093. cidr='2607:f0d0:1002:51::/124',
  1094. ip_version=6,
  1095. gateway_ip=constants.ATTR_NOT_SPECIFIED)
  1096. subnet2 = self.deserialize(self.fmt, res)
  1097. kwargs = {"fixed_ips":
  1098. [{'subnet_id': subnet['subnet']['id']},
  1099. {'subnet_id': subnet2['subnet']['id']}]}
  1100. res = self._create_port(self.fmt, net_id=net_id, **kwargs)
  1101. port1 = self.deserialize(self.fmt, res)
  1102. res = self._create_port(self.fmt, net_id=net_id, **kwargs)
  1103. port2 = self.deserialize(self.fmt, res)
  1104. fixed_ips = port1['port']['fixed_ips']
  1105. self.assertEqual(2, len(fixed_ips))
  1106. query_params = """
  1107. fixed_ips=ip_address_substr%%3D%s&fixed_ips=ip_address%%3D%s
  1108. """.strip() % (fixed_ips[0]['ip_address'][:-1],
  1109. fixed_ips[1]['ip_address'])
  1110. self._test_list_resources('port', [port1],
  1111. query_params=query_params)
  1112. query_params = """
  1113. fixed_ips=ip_address_substr%%3D%s&fixed_ips=ip_address%%3D%s
  1114. """.strip() % ('192.168.',
  1115. fixed_ips[1]['ip_address'])
  1116. self._test_list_resources('port', [],
  1117. query_params=query_params)
  1118. self._delete('ports', port1['port']['id'])
  1119. self._delete('ports', port2['port']['id'])
  1120. class TestMl2PortsV2WithRevisionPlugin(Ml2PluginV2TestCase):
  1121. def setUp(self):
  1122. super(TestMl2PortsV2WithRevisionPlugin, self).setUp()
  1123. self.revision_plugin = revision_plugin.RevisionPlugin()
  1124. def test_update_port_status_bumps_revision(self):
  1125. ctx = context.get_admin_context()
  1126. plugin = directory.get_plugin()
  1127. host_arg = {portbindings.HOST_ID: HOST}
  1128. with self.port(arg_list=(portbindings.HOST_ID,),
  1129. **host_arg) as port:
  1130. port = plugin.get_port(ctx, port['port']['id'])
  1131. updated_ports = []
  1132. receiver = lambda *a, **k: updated_ports.append(k['port'])
  1133. registry.subscribe(receiver, resources.PORT,
  1134. events.AFTER_UPDATE)
  1135. plugin.update_port_status(
  1136. ctx, port['id'],
  1137. constants.PORT_STATUS_ACTIVE, host=HOST)
  1138. self.assertGreater(updated_ports[0]['revision_number'],
  1139. port['revision_number'])
  1140. def test_bind_port_bumps_revision(self):
  1141. updated_ports = []
  1142. created_ports = []
  1143. ureceiver = lambda *a, **k: updated_ports.append(k['port'])
  1144. creceiver = lambda *a, **k: created_ports.append(k['port'])
  1145. registry.subscribe(ureceiver, resources.PORT,
  1146. events.AFTER_UPDATE)
  1147. registry.subscribe(creceiver, resources.PORT,
  1148. events.AFTER_CREATE)
  1149. host_arg = {portbindings.HOST_ID: HOST}
  1150. with self.port(arg_list=(portbindings.HOST_ID,),
  1151. **host_arg):
  1152. self.assertGreater(updated_ports[0]['revision_number'],
  1153. created_ports[0]['revision_number'])
  1154. def test_update_port_status_dvr_port_no_update_on_same_status(self):
  1155. ctx = context.get_admin_context()
  1156. plugin = directory.get_plugin()
  1157. # enable subscription for events
  1158. p_update_receiver = mock.Mock()
  1159. registry.subscribe(p_update_receiver, resources.PORT,
  1160. events.AFTER_UPDATE)
  1161. host_arg = {portbindings.HOST_ID: HOST}
  1162. with self.port(device_owner=constants.DEVICE_OWNER_DVR_INTERFACE,
  1163. device_id=TEST_ROUTER_ID,
  1164. arg_list=(portbindings.HOST_ID,),
  1165. **host_arg) as port:
  1166. ml2_db.ensure_distributed_port_binding(ctx, port['port']['id'],
  1167. HOST)
  1168. p_update_receiver.reset_mock()
  1169. plugin.update_port_status(
  1170. ctx, port['port']['id'],
  1171. constants.PORT_STATUS_ACTIVE, host=HOST)
  1172. self.assertTrue(p_update_receiver.called)
  1173. after_1 = plugin.get_port(ctx, port['port']['id'])
  1174. p_update_receiver.reset_mock()
  1175. plugin.update_port_status(
  1176. ctx, port['port']['id'],
  1177. constants.PORT_STATUS_ACTIVE, host=HOST)
  1178. self.assertFalse(p_update_receiver.called)
  1179. after_2 = plugin.get_port(ctx, port['port']['id'])
  1180. self.assertEqual(after_1['revision_number'],
  1181. after_2['revision_number'])
  1182. class TestMl2PortsV2WithL3(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
  1183. """For testing methods that require the L3 service plugin."""
  1184. l3_plugin = 'neutron.services.l3_router.l3_router_plugin.L3RouterPlugin'
  1185. def get_additional_service_plugins(self):
  1186. return {'flavors': 'flavors'}
  1187. def test_update_port_status_notify_port_event_after_update(self):
  1188. ctx = context.get_admin_context()
  1189. plugin = directory.get_plugin()
  1190. l3plugin = directory.get_plugin(plugin_constants.L3)
  1191. host_arg = {portbindings.HOST_ID: HOST}
  1192. with mock.patch.object(l3plugin.l3_rpc_notifier,
  1193. 'routers_updated_on_host') as mock_updated:
  1194. with self.port(device_owner=constants.DEVICE_OWNER_ROUTER_HA_INTF,
  1195. device_id=TEST_ROUTER_ID,
  1196. arg_list=(portbindings.HOST_ID,),
  1197. **host_arg) as port:
  1198. plugin.update_port_status(
  1199. ctx, port['port']['id'],
  1200. constants.PORT_STATUS_ACTIVE, host=HOST)
  1201. mock_updated.assert_called_once_with(
  1202. mock.ANY, [TEST_ROUTER_ID], HOST)
  1203. class TestMl2PluginOnly(Ml2PluginV2TestCase):
  1204. """For testing methods that don't call drivers"""
  1205. def test__verify_service_plugins_requirements(self):
  1206. plugin = directory.get_plugin()
  1207. with mock.patch.dict(ml2_plugin.SERVICE_PLUGINS_REQUIRED_DRIVERS,
  1208. {self.l3_plugin: self._mechanism_drivers}),\
  1209. mock.patch.object(plugin.extension_manager,
  1210. 'names',
  1211. return_value=self._mechanism_drivers):
  1212. plugin._verify_service_plugins_requirements()
  1213. def test__verify_service_plugins_requirements_missing_driver(self):
  1214. plugin = directory.get_plugin()
  1215. with mock.patch.dict(ml2_plugin.SERVICE_PLUGINS_REQUIRED_DRIVERS,
  1216. {self.l3_plugin: ['test_required_driver']}),\
  1217. mock.patch.object(plugin.extension_manager,
  1218. 'names',
  1219. return_value=self._mechanism_drivers):
  1220. self.assertRaises(
  1221. ml2_exc.ExtensionDriverNotFound,
  1222. plugin._verify_service_plugins_requirements
  1223. )
  1224. def _test_check_mac_update_allowed(self, vif_type, expect_change=True):
  1225. plugin = directory.get_plugin()
  1226. port = {'mac_address': "fake_mac", 'id': "fake_id"}
  1227. if expect_change:
  1228. new_attrs = {"mac_address": "dummy_mac"}
  1229. else:
  1230. new_attrs = {"mac_address": port['mac_address']}
  1231. binding = mock.Mock()
  1232. binding.vif_type = vif_type
  1233. mac_changed = plugin._check_mac_update_allowed(port, new_attrs,
  1234. binding)
  1235. self.assertEqual(expect_change, mac_changed)
  1236. def test_check_mac_update_allowed_if_no_mac_change(self):
  1237. self._test_check_mac_update_allowed(portbindings.VIF_TYPE_UNBOUND,
  1238. expect_change=False)
  1239. def test_check_mac_update_allowed_unless_bound(self):
  1240. with testtools.ExpectedException(exc.PortBound):
  1241. self._test_check_mac_update_allowed(portbindings.VIF_TYPE_OVS)
  1242. def test__device_to_port_id_prefix_names(self):
  1243. input_output = [('sg-abcdefg', 'abcdefg'),
  1244. ('tap123456', '123456'),
  1245. ('qvo567890', '567890')]
  1246. for device, expected in input_output:
  1247. self.assertEqual(expected,
  1248. ml2_plugin.Ml2Plugin._device_to_port_id(
  1249. self.context, device))
  1250. def test__device_to_port_id_mac_address(self):
  1251. with self.port() as p:
  1252. mac = p['port']['mac_address']
  1253. port_id = p['port']['id']
  1254. self.assertEqual(port_id,
  1255. ml2_plugin.Ml2Plugin._device_to_port_id(
  1256. self.context, mac))
  1257. def test__device_to_port_id_not_uuid_not_mac(self):
  1258. dev = '1234567'
  1259. self.assertEqual(dev, ml2_plugin.Ml2Plugin._device_to_port_id(
  1260. self.context, dev))
  1261. def test__device_to_port_id_UUID(self):
  1262. port_id = uuidutils.generate_uuid()
  1263. self.assertEqual(port_id, ml2_plugin.Ml2Plugin._device_to_port_id(
  1264. self.context, port_id))
  1265. class Test_GetNetworkMtu(Ml2PluginV2TestCase):
  1266. def test_get_mtu_with_physical_net(self):
  1267. plugin = directory.get_plugin()
  1268. mock_type_driver = mock.MagicMock()
  1269. plugin.type_manager.drivers['driver1'] = mock.Mock()
  1270. plugin.type_manager.drivers['driver1'].obj = mock_type_driver
  1271. net = {
  1272. 'name': 'net1',
  1273. 'network_type': 'driver1',
  1274. 'physical_network': 'physnet1',
  1275. }
  1276. plugin._get_network_mtu(net)
  1277. mock_type_driver.get_mtu.assert_called_once_with('physnet1')
  1278. def _register_type_driver_with_mtu(self, driver, mtu):
  1279. plugin = directory.get_plugin()
  1280. class FakeDriver(object):
  1281. def get_mtu(self, physical_network=None):
  1282. return mtu
  1283. def validate_provider_segment(self, segment):
  1284. pass
  1285. def is_partial_segment(self, segment):
  1286. return False
  1287. driver_mock = mock.Mock()
  1288. driver_mock.obj = FakeDriver()
  1289. plugin.type_manager.drivers[driver] = driver_mock
  1290. def test_single_segment(self):
  1291. plugin = directory.get_plugin()
  1292. self._register_type_driver_with_mtu('driver1', 1400)
  1293. net = {
  1294. 'name': 'net1',
  1295. mpnet.SEGMENTS: [
  1296. {
  1297. 'network_type': 'driver1',
  1298. 'physical_network': 'physnet1'
  1299. },
  1300. ]
  1301. }
  1302. self.assertEqual(1400, plugin._get_network_mtu(net))
  1303. def test_multiple_segments_returns_minimal_mtu(self):
  1304. plugin = directory.get_plugin()
  1305. self._register_type_driver_with_mtu('driver1', 1400)
  1306. self._register_type_driver_with_mtu('driver2', 1300)
  1307. net = {
  1308. 'name': 'net1',
  1309. mpnet.SEGMENTS: [
  1310. {
  1311. 'network_type': 'driver1',
  1312. 'physical_network': 'physnet1'
  1313. },
  1314. {
  1315. 'network_type': 'driver2',
  1316. 'physical_network': 'physnet2'
  1317. },
  1318. ]
  1319. }
  1320. self.assertEqual(1300, plugin._get_network_mtu(net))
  1321. def test_no_segments(self):
  1322. plugin = directory.get_plugin()
  1323. self._register_type_driver_with_mtu('driver1', 1400)
  1324. net = {
  1325. 'name': 'net1',
  1326. 'network_type': 'driver1',
  1327. 'physical_network': 'physnet1',
  1328. }
  1329. self.assertEqual(1400, plugin._get_network_mtu(net))
  1330. def test_get_mtu_None_returns_0(self):
  1331. plugin = directory.get_plugin()
  1332. self._register_type_driver_with_mtu('driver1', None)
  1333. net = {
  1334. 'name': 'net1',
  1335. 'network_type': 'driver1',
  1336. 'physical_network': 'physnet1',
  1337. }
  1338. self.assertEqual(1500, plugin._get_network_mtu(net))
  1339. def test_unknown_segment_type_ignored(self):
  1340. plugin = directory.get_plugin()
  1341. self._register_type_driver_with_mtu('driver1', None)
  1342. self._register_type_driver_with_mtu('driver2', 1300)
  1343. net = {
  1344. 'name': 'net1',
  1345. mpnet.SEGMENTS: [
  1346. {
  1347. 'network_type': 'driver1',
  1348. 'physical_network': 'physnet1'
  1349. },
  1350. {
  1351. 'network_type': 'driver2',
  1352. 'physical_network': 'physnet2'
  1353. },
  1354. ]
  1355. }
  1356. self.assertEqual(1300, plugin._get_network_mtu(net))
  1357. class TestMl2DvrPortsV2(TestMl2PortsV2):
  1358. def setUp(self):
  1359. super(TestMl2DvrPortsV2, self).setUp()
  1360. extensions = ['router',
  1361. constants.L3_AGENT_SCHEDULER_EXT_ALIAS,
  1362. constants.L3_DISTRIBUTED_EXT_ALIAS]
  1363. self.plugin = directory.get_plugin()
  1364. self.l3plugin = mock.Mock()
  1365. type(self.l3plugin).supported_extension_aliases = (
  1366. mock.PropertyMock(return_value=extensions))
  1367. def test_delete_port_notifies_l3_plugin(self, floating_ip=False):
  1368. directory.add_plugin(plugin_constants.L3, self.l3plugin)
  1369. ns_to_delete = {'host': 'myhost', 'agent_id': 'vm_l3_agent',
  1370. 'router_id': 'my_router'}
  1371. router_ids = set()
  1372. if floating_ip:
  1373. router_ids.add(ns_to_delete['router_id'])
  1374. with self.port() as port,\
  1375. mock.patch.object(registry, 'notify') as notify,\
  1376. mock.patch.object(self.l3plugin,
  1377. 'disassociate_floatingips',
  1378. return_value=router_ids):
  1379. port_id = port['port']['id']
  1380. self.plugin.delete_port(self.context, port_id)
  1381. self.assertEqual(2, notify.call_count)
  1382. # needed for a full match in the assertion below
  1383. port['port']['extra_dhcp_opts'] = []
  1384. expected = [mock.call(resources.PORT, events.BEFORE_DELETE,
  1385. mock.ANY, context=self.context,
  1386. port_id=port['port']['id'], port_check=True),
  1387. mock.call(resources.PORT, events.AFTER_DELETE,
  1388. mock.ANY, context=self.context,
  1389. port=port['port'],
  1390. router_ids=router_ids)]
  1391. notify.assert_has_calls(expected)
  1392. def test_delete_port_with_floatingip_notifies_l3_plugin(self):
  1393. self.test_delete_port_notifies_l3_plugin(floating_ip=True)
  1394. def test_concurrent_csnat_port_delete(self):
  1395. plugin = directory.get_plugin(plugin_constants.L3)
  1396. r = plugin.create_router(
  1397. self.context,
  1398. {'router': {'name': 'router', 'admin_state_up': True,
  1399. 'tenant_id': 'fake_tenant'}})
  1400. with self.subnet() as s:
  1401. p = plugin.add_router_interface(self.context, r['id'],
  1402. {'subnet_id': s['subnet']['id']})
  1403. # lie to turn the port into an SNAT interface
  1404. with db_api.context_manager.reader.using(self.context):
  1405. pager = base_obj.Pager(limit=1)
  1406. rp = l3_obj.RouterPort.get_objects(
  1407. self.context, _pager=pager, port_id=p['port_id'])
  1408. rp[0].port_type = constants.DEVICE_OWNER_ROUTER_SNAT
  1409. rp[0].update()
  1410. # take the port away before csnat gets a chance to delete it
  1411. # to simulate a concurrent delete
  1412. orig_get_ports = plugin._core_plugin.get_ports
  1413. def get_ports_with_delete_first(*args, **kwargs):
  1414. plugin._core_plugin.delete_port(self.context,
  1415. p['port_id'],
  1416. l3_port_check=False)
  1417. return orig_get_ports(*args, **kwargs)
  1418. plugin._core_plugin.get_ports = get_ports_with_delete_first
  1419. # This should be able to handle a concurrent delete without raising
  1420. # an exception
  1421. router = plugin._get_router(self.context, r['id'])
  1422. plugin.delete_csnat_router_interface_ports(self.context, router)
  1423. class TestMl2PortBinding(Ml2PluginV2TestCase,
  1424. test_bindings.PortBindingsTestCase):
  1425. # Test case does not set binding:host_id, so ml2 does not attempt
  1426. # to bind port
  1427. VIF_TYPE = portbindings.VIF_TYPE_UNBOUND
  1428. HAS_PORT_FILTER = False
  1429. ENABLE_SG = True
  1430. FIREWALL_DRIVER = test_sg_rpc.FIREWALL_HYBRID_DRIVER
  1431. def setUp(self, firewall_driver=None):
  1432. test_sg_rpc.set_firewall_driver(self.FIREWALL_DRIVER)
  1433. cfg.CONF.set_override(
  1434. 'enable_security_group', self.ENABLE_SG,
  1435. group='SECURITYGROUP')
  1436. super(TestMl2PortBinding, self).setUp()
  1437. def _check_port_binding_profile(self, port, profile=None):
  1438. self.assertIn('id', port)
  1439. self.assertIn(portbindings.PROFILE, port)
  1440. value = port[portbindings.PROFILE]
  1441. self.assertEqual(profile or {}, value)
  1442. def test_create_port_binding_profile(self):
  1443. self._test_create_port_binding_profile({'a': 1, 'b': 2})
  1444. def test_update_port_binding_profile(self):
  1445. self._test_update_port_binding_profile({'c': 3})
  1446. def test_create_port_binding_profile_too_big(self):
  1447. s = 'x' * 5000
  1448. profile_arg = {portbindings.PROFILE: {'d': s}}
  1449. try:
  1450. with self.port(expected_res_status=400,
  1451. arg_list=(portbindings.PROFILE,),
  1452. **profile_arg):
  1453. pass
  1454. except webob.exc.HTTPClientError:
  1455. pass
  1456. def test_remove_port_binding_profile(self):
  1457. profile = {'e': 5}
  1458. profile_arg = {portbindings.PROFILE: profile}
  1459. with self.port(arg_list=(portbindings.PROFILE,),
  1460. **profile_arg) as port:
  1461. self._check_port_binding_profile(port['port'], profile)
  1462. port_id = port['port']['id']
  1463. profile_arg = {portbindings.PROFILE: None}
  1464. port = self._update('ports', port_id,
  1465. {'port': profile_arg})['port']
  1466. self._check_port_binding_profile(port)
  1467. port = self._show('ports', port_id)['port']
  1468. self._check_port_binding_profile(port)
  1469. def test_return_on_concurrent_delete_and_binding(self):
  1470. # create a port and delete it so we have an expired mechanism context
  1471. with self.port() as port:
  1472. plugin = directory.get_plugin()
  1473. binding = plugin._get_port(self.context,
  1474. port['port']['id']).port_binding
  1475. binding['host'] = 'test'
  1476. mech_context = driver_context.PortContext(
  1477. plugin, self.context, port['port'],
  1478. plugin.get_network(self.context, port['port']['network_id']),
  1479. binding, None)
  1480. side = exc.PortNotFound(port_id=port['port']['id'])
  1481. with mock.patch.object(plugin, '_get_port',
  1482. side_effect=side) as gp_mock,\
  1483. mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin.'
  1484. '_make_port_dict') as mpd_mock:
  1485. plugin._bind_port_if_needed(mech_context)
  1486. # called during deletion to get port
  1487. self.assertTrue(gp_mock.mock_calls)
  1488. # should have returned before calling _make_port_dict
  1489. self.assertFalse(mpd_mock.mock_calls)
  1490. def _create_port_and_bound_context(self, port_vif_type, bound_vif_type):
  1491. with self.port() as port:
  1492. plugin = directory.get_plugin()
  1493. binding = plugin._get_port(
  1494. self.context, port['port']['id']).port_binding
  1495. binding['host'] = 'fake_host'
  1496. binding['vif_type'] = port_vif_type
  1497. # Generates port context to be used before the bind.
  1498. port_context = driver_context.PortContext(
  1499. plugin, self.context, port['port'],
  1500. plugin.get_network(self.context, port['port']['network_id']),
  1501. binding, None)
  1502. bound_context = mock.MagicMock()
  1503. # Bound context is how port_context is expected to look
  1504. # after _bind_port.
  1505. bound_context.vif_type = bound_vif_type
  1506. return plugin, port_context, bound_context
  1507. def test__attempt_binding(self):
  1508. # Simulate a successful binding for vif_type unbound
  1509. # and keep the same binding state for other vif types.
  1510. vif_types = [(portbindings.VIF_TYPE_BINDING_FAILED,
  1511. portbindings.VIF_TYPE_BINDING_FAILED),
  1512. (portbindings.VIF_TYPE_UNBOUND,
  1513. portbindings.VIF_TYPE_OVS),
  1514. (portbindings.VIF_TYPE_OVS,
  1515. portbindings.VIF_TYPE_OVS)]
  1516. for port_vif_type, bound_vif_type in vif_types:
  1517. plugin, port_context, bound_context = (
  1518. self._create_port_and_bound_context(port_vif_type,
  1519. bound_vif_type))
  1520. with mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin._bind_port',
  1521. return_value=bound_context) as bd_mock:
  1522. context, need_notify, try_again = (plugin._attempt_binding(
  1523. port_context, False))
  1524. expected_need_notify = port_vif_type not in (
  1525. portbindings.VIF_TYPE_BINDING_FAILED,
  1526. portbindings.VIF_TYPE_OVS)
  1527. if bound_vif_type == portbindings.VIF_TYPE_BINDING_FAILED:
  1528. expected_vif_type = port_vif_type
  1529. expected_try_again = True
  1530. expected_bd_mock_called = True
  1531. else:
  1532. expected_vif_type = portbindings.VIF_TYPE_OVS
  1533. expected_try_again = False
  1534. expected_bd_mock_called = (port_vif_type ==
  1535. portbindings.VIF_TYPE_UNBOUND)
  1536. self.assertEqual(expected_need_notify, need_notify)
  1537. self.assertEqual(expected_vif_type, context.vif_type)
  1538. self.assertEqual(expected_try_again, try_again)
  1539. self.assertEqual(expected_bd_mock_called, bd_mock.called)
  1540. def test__bind_port_if_needed_early_exit_on_no_segments(self):
  1541. with self.network() as n:
  1542. ctx = context.get_admin_context()
  1543. seg_plugin = segments_plugin.Plugin.get_instance()
  1544. seg = seg_plugin.get_segments(ctx)[0]
  1545. seg_plugin.delete_segment(ctx, seg['id'])
  1546. plugin = directory.get_plugin()
  1547. mech_context = driver_context.PortContext(
  1548. plugin, ctx, None,
  1549. plugin.get_network(self.context, n['network']['id']),
  1550. models.PortBinding(), None)
  1551. with mock.patch.object(plugin, '_attempt_binding') as ab:
  1552. plugin._bind_port_if_needed(mech_context)
  1553. self.assertFalse(ab.called)
  1554. def test__attempt_binding_retries(self):
  1555. # Simulate cases of both successful and failed binding states for
  1556. # vif_type unbound
  1557. vif_types = [(portbindings.VIF_TYPE_UNBOUND,
  1558. portbindings.VIF_TYPE_BINDING_FAILED),
  1559. (portbindings.VIF_TYPE_UNBOUND,
  1560. portbindings.VIF_TYPE_OVS)]
  1561. for port_vif_type, bound_vif_type in vif_types:
  1562. plugin, port_context, bound_context = (
  1563. self._create_port_and_bound_context(port_vif_type,
  1564. bound_vif_type))
  1565. with mock.patch(
  1566. 'neutron.plugins.ml2.plugin.Ml2Plugin._bind_port',
  1567. return_value=bound_context),\
  1568. mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin._commit_'
  1569. 'port_binding',
  1570. return_value=(bound_context, True, False)),\
  1571. mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin.'
  1572. '_attempt_binding',
  1573. side_effect=plugin._attempt_binding) as at_mock:
  1574. plugin._bind_port_if_needed(port_context)
  1575. if bound_vif_type == portbindings.VIF_TYPE_BINDING_FAILED:
  1576. # An unsuccessful binding attempt should be retried
  1577. # MAX_BIND_TRIES amount of times.
  1578. self.assertEqual(ml2_plugin.MAX_BIND_TRIES,
  1579. at_mock.call_count)
  1580. else:
  1581. # Successful binding should only be attempted once.
  1582. self.assertEqual(1, at_mock.call_count)
  1583. def test_port_binding_profile_not_changed(self):
  1584. profile = {'e': 5}
  1585. profile_arg = {portbindings.PROFILE: profile}
  1586. with self.port(arg_list=(portbindings.PROFILE,),
  1587. **profile_arg) as port:
  1588. self._check_port_binding_profile(port['port'], profile)
  1589. port_id = port['port']['id']
  1590. state_arg = {'admin_state_up': True}
  1591. port = self._update('ports', port_id,
  1592. {'port': state_arg})['port']
  1593. self._check_port_binding_profile(port, profile)
  1594. port = self._show('ports', port_id)['port']
  1595. self._check_port_binding_profile(port, profile)
  1596. def test_update_port_binding_host_id_none(self):
  1597. with self.port() as port:
  1598. plugin = directory.get_plugin()
  1599. binding = plugin._get_port(
  1600. self.context, port['port']['id']).port_binding
  1601. with self.context.session.begin(subtransactions=True):
  1602. binding.host = 'test'
  1603. mech_context = driver_context.PortContext(
  1604. plugin, self.context, port['port'],
  1605. plugin.get_network(self.context, port['port']['network_id']),
  1606. binding, None)
  1607. with mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin.'
  1608. '_update_port_dict_binding') as update_mock:
  1609. attrs = {portbindings.HOST_ID: None}
  1610. self.assertEqual('test', binding.host)
  1611. with self.context.session.begin(subtransactions=True):
  1612. plugin._process_port_binding(mech_context, attrs)
  1613. self.assertTrue(update_mock.mock_calls)
  1614. self.assertEqual('', binding.host)
  1615. def test_update_port_binding_host_id_not_changed(self):
  1616. with self.port() as port:
  1617. plugin = directory.get_plugin()
  1618. binding = plugin._get_port(
  1619. self.context, port['port']['id']).port_binding
  1620. binding['host'] = 'test'
  1621. mech_context = driver_context.PortContext(
  1622. plugin, self.context, port['port'],
  1623. plugin.get_network(self.context, port['port']['network_id']),
  1624. binding, None)
  1625. with mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin.'
  1626. '_update_port_dict_binding') as update_mock:
  1627. attrs = {portbindings.PROFILE: {'e': 5}}
  1628. plugin._process_port_binding(mech_context, attrs)
  1629. self.assertTrue(update_mock.mock_calls)
  1630. self.assertEqual('test', binding.host)
  1631. def test_process_distributed_port_binding_update_router_id(self):
  1632. host_id = 'host'
  1633. binding = models.DistributedPortBinding(
  1634. port_id='port_id',
  1635. host=host_id,
  1636. router_id='old_router_id',
  1637. vif_type=portbindings.VIF_TYPE_OVS,
  1638. vnic_type=portbindings.VNIC_NORMAL,
  1639. status=constants.PORT_STATUS_DOWN)
  1640. plugin = directory.get_plugin()
  1641. mock_network = {'id': 'net_id'}
  1642. mock_port = {'id': 'port_id'}
  1643. ctxt = context.get_admin_context()
  1644. new_router_id = 'new_router'
  1645. attrs = {'device_id': new_router_id, portbindings.HOST_ID: host_id}
  1646. with mock.patch.object(plugin, '_update_port_dict_binding'):
  1647. with mock.patch.object(segments_db, 'get_network_segments',
  1648. return_value=[]):
  1649. mech_context = driver_context.PortContext(
  1650. self, ctxt, mock_port, mock_network, binding, None)
  1651. plugin._process_distributed_port_binding(mech_context,
  1652. ctxt, attrs)
  1653. self.assertEqual(new_router_id,
  1654. mech_context._binding.router_id)
  1655. self.assertEqual(host_id, mech_context._binding.host)
  1656. def test_update_distributed_port_binding_on_concurrent_port_delete(self):
  1657. plugin = directory.get_plugin()
  1658. with self.port() as port:
  1659. port = {
  1660. 'id': port['port']['id'],
  1661. portbindings.HOST_ID: 'foo_host',
  1662. }
  1663. exc = db_exc.DBReferenceError('', '', '', '')
  1664. with mock.patch.object(ml2_db, 'ensure_distributed_port_binding',
  1665. side_effect=exc):
  1666. res = plugin.update_distributed_port_binding(
  1667. self.context, port['id'], {'port': port})
  1668. self.assertIsNone(res)
  1669. def test_update_distributed_port_binding_on_non_existent_port(self):
  1670. plugin = directory.get_plugin()
  1671. port = {
  1672. 'id': 'foo_port_id',
  1673. portbindings.HOST_ID: 'foo_host',
  1674. }
  1675. with mock.patch.object(
  1676. ml2_db, 'ensure_distributed_port_binding') as mock_dist:
  1677. plugin.update_distributed_port_binding(
  1678. self.context, 'foo_port_id', {'port': port})
  1679. self.assertFalse(mock_dist.called)
  1680. def test__bind_port_original_port_set(self):
  1681. plugin = directory.get_plugin()
  1682. plugin.mechanism_manager = mock.Mock()
  1683. mock_port = {'id': 'port_id'}
  1684. context = mock.Mock()
  1685. context.network.current = {'id': 'net_id'}
  1686. context.original = mock_port
  1687. with mock.patch.object(plugin, '_update_port_dict_binding'), \
  1688. mock.patch.object(segments_db, 'get_network_segments',
  1689. return_value=[]):
  1690. new_context = plugin._bind_port(context)
  1691. self.assertEqual(mock_port, new_context.original)
  1692. self.assertFalse(new_context == context)
  1693. class TestMl2PortBindingNoSG(TestMl2PortBinding):
  1694. HAS_PORT_FILTER = False
  1695. ENABLE_SG = False
  1696. FIREWALL_DRIVER = test_sg_rpc.FIREWALL_NOOP_DRIVER
  1697. class TestMl2PortBindingHost(Ml2PluginV2TestCase,
  1698. test_bindings.PortBindingsHostTestCaseMixin):
  1699. pass
  1700. class TestMl2PortBindingVnicType(Ml2PluginV2TestCase,
  1701. test_bindings.PortBindingsVnicTestCaseMixin):
  1702. pass
  1703. class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
  1704. def setUp(self, plugin=None):
  1705. super(TestMultiSegmentNetworks, self).setUp()
  1706. def test_allocate_dynamic_segment(self):
  1707. data = {'network': {'name': 'net1',
  1708. 'tenant_id': 'tenant_one'}}
  1709. network_req = self.new_create_request('networks', data)
  1710. network = self.deserialize(self.fmt,
  1711. network_req.get_response(self.api))
  1712. segment = {driver_api.NETWORK_TYPE: 'vlan',
  1713. driver_api.PHYSICAL_NETWORK: 'physnet1'}
  1714. network_id = network['network']['id']
  1715. self.driver.type_manager.allocate_dynamic_segment(
  1716. self.context, network_id, segment)
  1717. dynamic_segment = segments_db.get_dynamic_segment(
  1718. self.context, network_id, 'physnet1')
  1719. self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
  1720. self.assertEqual('physnet1',
  1721. dynamic_segment[driver_api.PHYSICAL_NETWORK])
  1722. self.assertGreater(dynamic_segment[driver_api.SEGMENTATION_ID], 0)
  1723. segment2 = {driver_api.NETWORK_TYPE: 'vlan',
  1724. driver_api.SEGMENTATION_ID: 1234,
  1725. driver_api.PHYSICAL_NETWORK: 'physnet3'}
  1726. self.driver.type_manager.allocate_dynamic_segment(
  1727. self.context, network_id, segment2)
  1728. dynamic_segment = segments_db.get_dynamic_segment(
  1729. self.context, network_id, segmentation_id='1234')
  1730. self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
  1731. self.assertEqual('physnet3',
  1732. dynamic_segment[driver_api.PHYSICAL_NETWORK])
  1733. self.assertEqual(dynamic_segment[driver_api.SEGMENTATION_ID], 1234)
  1734. def test_allocate_dynamic_segment_multiple_physnets(self):
  1735. data = {'network': {'name': 'net1',
  1736. 'tenant_id': 'tenant_one'}}
  1737. network_req = self.new_create_request('networks', data)
  1738. network = self.deserialize(self.fmt,
  1739. network_req.get_response(self.api))
  1740. segment = {driver_api.NETWORK_TYPE: 'vlan',
  1741. driver_api.PHYSICAL_NETWORK: 'physnet1'}
  1742. network_id = network['network']['id']
  1743. self.driver.type_manager.allocate_dynamic_segment(
  1744. self.context, network_id, segment)
  1745. dynamic_segment = segments_db.get_dynamic_segment(
  1746. self.context, network_id, 'physnet1')
  1747. self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
  1748. self.assertEqual('physnet1',
  1749. dynamic_segment[driver_api.PHYSICAL_NETWORK])
  1750. dynamic_segmentation_id = dynamic_segment[driver_api.SEGMENTATION_ID]
  1751. self.assertGreater(dynamic_segmentation_id, 0)
  1752. dynamic_segment1 = segments_db.get_dynamic_segment(
  1753. self.context, network_id, 'physnet1')
  1754. dynamic_segment1_id = dynamic_segment1[driver_api.SEGMENTATION_ID]
  1755. self.assertEqual(dynamic_segmentation_id, dynamic_segment1_id)
  1756. segment2 = {driver_api.NETWORK_TYPE: 'vlan',
  1757. driver_api.PHYSICAL_NETWORK: 'physnet2'}
  1758. self.driver.type_manager.allocate_dynamic_segment(
  1759. self.context, network_id, segment2)
  1760. dynamic_segment2 = segments_db.get_dynamic_segment(
  1761. self.context, network_id, 'physnet2')
  1762. dynamic_segmentation2_id = dynamic_segment2[driver_api.SEGMENTATION_ID]
  1763. self.assertNotEqual(dynamic_segmentation_id, dynamic_segmentation2_id)
  1764. def test_allocate_release_dynamic_segment(self):
  1765. data = {'network': {'name': 'net1',
  1766. 'tenant_id': 'tenant_one'}}
  1767. network_req = self.new_create_request('networks', data)
  1768. network = self.deserialize(self.fmt,
  1769. network_req.get_response(self.api))
  1770. segment = {driver_api.NETWORK_TYPE: 'vlan',
  1771. driver_api.PHYSICAL_NETWORK: 'physnet1'}
  1772. network_id = network['network']['id']
  1773. self.driver.type_manager.allocate_dynamic_segment(
  1774. self.context, network_id, segment)
  1775. dynamic_segment = segments_db.get_dynamic_segment(
  1776. self.context, network_id, 'physnet1')
  1777. self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
  1778. self.assertEqual('physnet1',
  1779. dynamic_segment[driver_api.PHYSICAL_NETWORK])
  1780. dynamic_segmentation_id = dynamic_segment[driver_api.SEGMENTATION_ID]
  1781. self.assertGreater(dynamic_segmentation_id, 0)
  1782. self.driver.type_manager.release_dynamic_segment(
  1783. self.context, dynamic_segment[driver_api.ID])
  1784. self.assertIsNone(segments_db.get_dynamic_segment(
  1785. self.context, network_id, 'physnet1'))
  1786. def test_create_network_provider(self):
  1787. data = {'network': {'name': 'net1',
  1788. pnet.NETWORK_TYPE: 'vlan',
  1789. pnet.PHYSICAL_NETWORK: 'physnet1',
  1790. pnet.SEGMENTATION_ID: 1,
  1791. 'tenant_id': 'tenant_one'}}
  1792. network_req = self.new_create_request('networks', data)
  1793. network = self.deserialize(self.fmt,
  1794. network_req.get_response(self.api))
  1795. self.assertEqual('vlan', network['network'][pnet.NETWORK_TYPE])
  1796. self.assertEqual('physnet1', network['network'][pnet.PHYSICAL_NETWORK])
  1797. self.assertEqual(1, network['network'][pnet.SEGMENTATION_ID])
  1798. self.assertNotIn(mpnet.SEGMENTS, network['network'])
  1799. def test_create_network_single_multiprovider(self):
  1800. data = {'network': {'name': 'net1',
  1801. mpnet.SEGMENTS:
  1802. [{pnet.NETWORK_TYPE: 'vlan',
  1803. pnet.PHYSICAL_NETWORK: 'physnet1',
  1804. pnet.SEGMENTATION_ID: 1}],
  1805. 'tenant_id': 'tenant_one'}}
  1806. net_req = self.new_create_request('networks', data)
  1807. network = self.deserialize(self.fmt, net_req.get_response(self.api))
  1808. self.assertEqual('vlan', network['network'][pnet.NETWORK_TYPE])
  1809. self.assertEqual('physnet1', network['network'][pnet.PHYSICAL_NETWORK])
  1810. self.assertEqual(1, network['network'][pnet.SEGMENTATION_ID])
  1811. self.assertNotIn(mpnet.SEGMENTS, network['network'])
  1812. # Tests get_network()
  1813. net_req = self.new_show_request('networks', network['network']['id'])
  1814. network = self.deserialize(self.fmt, net_req.get_response(self.api))
  1815. self.assertEqual('vlan', network['network'][pnet.NETWORK_TYPE])
  1816. self.assertEqual('physnet1', network['network'][pnet.PHYSICAL_NETWORK])
  1817. self.assertEqual(1, network['network'][pnet.SEGMENTATION_ID])
  1818. self.assertNotIn(mpnet.SEGMENTS, network['network'])
  1819. def test_create_network_multiprovider(self):
  1820. data = {'network': {'name': 'net1',
  1821. mpnet.SEGMENTS:
  1822. [{pnet.NETWORK_TYPE: 'vlan',
  1823. pnet.PHYSICAL_NETWORK: 'physnet1',
  1824. pnet.SEGMENTATION_ID: 1},
  1825. {pnet.NETWORK_TYPE: 'vlan',
  1826. pnet.PHYSICAL_NETWORK: 'physnet1',
  1827. pnet.SEGMENTATION_ID: 2}],
  1828. 'tenant_id': 'tenant_one'}}
  1829. network_req = self.new_create_request('networks', data)
  1830. network = self.deserialize(self.fmt,
  1831. network_req.get_response(self.api))
  1832. segments = network['network'][mpnet.SEGMENTS]
  1833. for segment_index, segment in enumerate(data['network']
  1834. [mpnet.SEGMENTS]):
  1835. for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
  1836. pnet.SEGMENTATION_ID]:
  1837. self.assertEqual(segment.get(field),
  1838. segments[segment_index][field])
  1839. # Tests get_network()
  1840. net_req = self.new_show_request('networks', network['network']['id'])
  1841. network = self.deserialize(self.fmt, net_req.get_response(self.api))
  1842. segments = network['network'][mpnet.SEGMENTS]
  1843. for segment_index, segment in enumerate(data['network']
  1844. [mpnet.SEGMENTS]):
  1845. for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
  1846. pnet.SEGMENTATION_ID]:
  1847. self.assertEqual(segment.get(field),
  1848. segments[segment_index][field])
  1849. def test_create_network_with_provider_and_multiprovider_fail(self):
  1850. data = {'network': {'name': 'net1',
  1851. mpnet.SEGMENTS:
  1852. [{pnet.NETWORK_TYPE: 'vlan',
  1853. pnet.PHYSICAL_NETWORK: 'physnet1',
  1854. pnet.SEGMENTATION_ID: 1}],
  1855. pnet.NETWORK_TYPE: 'vlan',
  1856. pnet.PHYSICAL_NETWORK: 'physnet1',
  1857. pnet.SEGMENTATION_ID: 1,
  1858. 'tenant_id': 'tenant_one'}}
  1859. network_req = self.new_create_request('networks', data)
  1860. res = network_req.get_response(self.api)
  1861. self.assertEqual(400, res.status_int)
  1862. def test_create_network_duplicate_full_segments(self):
  1863. data = {'network': {'name': 'net1',
  1864. mpnet.SEGMENTS:
  1865. [{pnet.NETWORK_TYPE: 'vlan',
  1866. pnet.PHYSICAL_NETWORK: 'physnet1',
  1867. pnet.SEGMENTATION_ID: 1},
  1868. {pnet.NETWORK_TYPE: 'vlan',
  1869. pnet.PHYSICAL_NETWORK: 'physnet1',
  1870. pnet.SEGMENTATION_ID: 1}],
  1871. 'tenant_id': 'tenant_one'}}
  1872. network_req = self.new_create_request('networks', data)
  1873. res = network_req.get_response(self.api)
  1874. self.assertEqual(400, res.status_int)
  1875. def test_create_network_duplicate_partial_segments(self):
  1876. data = {'network': {'name': 'net1',
  1877. mpnet.SEGMENTS:
  1878. [{pnet.NETWORK_TYPE: 'vlan',
  1879. pnet.PHYSICAL_NETWORK: 'physnet1'},
  1880. {pnet.NETWORK_TYPE: 'vlan',
  1881. pnet.PHYSICAL_NETWORK: 'physnet1'}],
  1882. 'tenant_id': 'tenant_one'}}
  1883. network_req = self.new_create_request('networks', data)
  1884. res = network_req.get_response(self.api)
  1885. self.assertEqual(201, res.status_int)
  1886. def test_release_network_segments(self):
  1887. data = {'network': {'name': 'net1',
  1888. 'admin_state_up': True,
  1889. 'shared': False,
  1890. pnet.NETWORK_TYPE: 'vlan',
  1891. pnet.PHYSICAL_NETWORK: 'physnet1',
  1892. pnet.SEGMENTATION_ID: 1,
  1893. 'tenant_id': 'tenant_one'}}
  1894. network_req = self.new_create_request('networks', data)
  1895. res = network_req.get_response(self.api)
  1896. network = self.deserialize(self.fmt, res)
  1897. network_id = network['network']['id']
  1898. segment = {driver_api.NETWORK_TYPE: 'vlan',
  1899. driver_api.PHYSICAL_NETWORK: 'physnet2'}
  1900. self.driver.type_manager.allocate_dynamic_segment(
  1901. self.context, network_id, segment)
  1902. dynamic_segment = segments_db.get_dynamic_segment(
  1903. self.context, network_id, 'physnet2')
  1904. self.assertEqual('vlan', dynamic_segment[driver_api.NETWORK_TYPE])
  1905. self.assertEqual('physnet2',
  1906. dynamic_segment[driver_api.PHYSICAL_NETWORK])
  1907. self.assertGreater(dynamic_segment[driver_api.SEGMENTATION_ID], 0)
  1908. with mock.patch.object(type_vlan.VlanTypeDriver,
  1909. 'release_segment') as rs:
  1910. segments_plugin_db.subscribe()
  1911. req = self.new_delete_request('networks', network_id)
  1912. res = req.get_response(self.api)
  1913. self.assertEqual(2, rs.call_count)
  1914. self.assertEqual([], segments_db.get_network_segments(
  1915. self.context, network_id))
  1916. self.assertIsNone(segments_db.get_dynamic_segment(
  1917. self.context, network_id, 'physnet2'))
  1918. def test_release_segment_no_type_driver(self):
  1919. data = {'network': {'name': 'net1',
  1920. 'admin_state_up': True,
  1921. 'shared': False,
  1922. pnet.NETWORK_TYPE: 'vlan',
  1923. pnet.PHYSICAL_NETWORK: 'physnet1',
  1924. pnet.SEGMENTATION_ID: 1,
  1925. 'tenant_id': 'tenant_one'}}
  1926. network_req = self.new_create_request('networks', data)
  1927. res = network_req.get_response(self.api)
  1928. network = self.deserialize(self.fmt, res)
  1929. network_id = network['network']['id']
  1930. segment = {driver_api.NETWORK_TYPE: 'faketype',
  1931. driver_api.PHYSICAL_NETWORK: 'physnet1',
  1932. driver_api.ID: 1}
  1933. with mock.patch('neutron.plugins.ml2.managers.LOG') as log:
  1934. with mock.patch('neutron.plugins.ml2.managers.segments_db') as db:
  1935. db.get_network_segments.return_value = (segment,)
  1936. self.driver.type_manager.release_network_segments(
  1937. self.context, network_id)
  1938. log.error.assert_called_once_with(
  1939. "Failed to release segment '%s' because "
  1940. "network type is not supported.", segment)
  1941. def test_create_provider_fail(self):
  1942. segment = {pnet.NETWORK_TYPE: None,
  1943. pnet.PHYSICAL_NETWORK: 'phys_net',
  1944. pnet.SEGMENTATION_ID: None}
  1945. with testtools.ExpectedException(exc.InvalidInput):
  1946. self.driver.type_manager._process_provider_create(segment)
  1947. def test_create_network_plugin(self):
  1948. data = {'network': {'name': 'net1',
  1949. 'admin_state_up': True,
  1950. 'shared': False,
  1951. pnet.NETWORK_TYPE: 'vlan',
  1952. pnet.PHYSICAL_NETWORK: 'physnet1',
  1953. pnet.SEGMENTATION_ID: 1,
  1954. 'tenant_id': 'tenant_one'}}
  1955. def raise_mechanism_exc(*args, **kwargs):
  1956. raise ml2_exc.MechanismDriverError(
  1957. method='create_network_postcommit')
  1958. with mock.patch('neutron.plugins.ml2.managers.MechanismManager.'
  1959. 'create_network_precommit', new=raise_mechanism_exc):
  1960. with testtools.ExpectedException(ml2_exc.MechanismDriverError):
  1961. self.driver.create_network(self.context, data)
  1962. def test_extend_dictionary_no_segments(self):
  1963. network = dict(name='net_no_segment', id='5', tenant_id='tenant_one')
  1964. self.driver.type_manager.extend_network_dict_provider(self.context,
  1965. network)
  1966. self.assertIsNone(network[pnet.NETWORK_TYPE])
  1967. self.assertIsNone(network[pnet.PHYSICAL_NETWORK])
  1968. self.assertIsNone(network[pnet.SEGMENTATION_ID])
  1969. class TestMl2AllowedAddressPairs(Ml2PluginV2TestCase,
  1970. test_pair.TestAllowedAddressPairs):
  1971. _extension_drivers = ['port_security']
  1972. def setUp(self, plugin=None):
  1973. cfg.CONF.set_override('extension_drivers',
  1974. self._extension_drivers,
  1975. group='ml2')
  1976. super(test_pair.TestAllowedAddressPairs, self).setUp(
  1977. plugin=PLUGIN_NAME)
  1978. class TestMl2PortSecurity(Ml2PluginV2TestCase):
  1979. def setUp(self):
  1980. cfg.CONF.set_override('extension_drivers',
  1981. ['port_security'],
  1982. group='ml2')
  1983. cfg.CONF.set_override('enable_security_group',
  1984. False,
  1985. group='SECURITYGROUP')
  1986. super(TestMl2PortSecurity, self).setUp()
  1987. def test_port_update_without_security_groups(self):
  1988. with self.port() as port:
  1989. plugin = directory.get_plugin()
  1990. ctx = context.get_admin_context()
  1991. self.assertTrue(port['port']['port_security_enabled'])
  1992. updated_port = plugin.update_port(
  1993. ctx, port['port']['id'],
  1994. {'port': {'port_security_enabled': False}})
  1995. self.assertFalse(updated_port['port_security_enabled'])
  1996. class TestMl2HostsNetworkAccess(Ml2PluginV2TestCase):
  1997. _mechanism_drivers = ['openvswitch', 'logger']
  1998. def setUp(self):
  1999. super(TestMl2HostsNetworkAccess, self).setUp()
  2000. helpers.register_ovs_agent(
  2001. host='host1', bridge_mappings={'physnet1': 'br-eth-1'})
  2002. helpers.register_ovs_agent(
  2003. host='host2', bridge_mappings={'physnet2': 'br-eth-2'})
  2004. helpers.register_ovs_agent(
  2005. host='host3', bridge_mappings={'physnet3': 'br-eth-3'})
  2006. self.dhcp_agent1 = helpers.register_dhcp_agent(
  2007. host='host1')
  2008. self.dhcp_agent2 = helpers.register_dhcp_agent(
  2009. host='host2')
  2010. self.dhcp_agent3 = helpers.register_dhcp_agent(
  2011. host='host3')
  2012. self.dhcp_hosts = {'host1', 'host2', 'host3'}
  2013. def test_filter_hosts_with_network_access(self):
  2014. net = self.driver.create_network(
  2015. self.context,
  2016. {'network': {'name': 'net1',
  2017. pnet.NETWORK_TYPE: 'vlan',
  2018. pnet.PHYSICAL_NETWORK: 'physnet1',
  2019. pnet.SEGMENTATION_ID: 1,
  2020. 'tenant_id': 'tenant_one',
  2021. 'admin_state_up': True,
  2022. 'shared': True}})
  2023. observeds = self.driver.filter_hosts_with_network_access(
  2024. self.context, net['id'], self.dhcp_hosts)
  2025. self.assertEqual({self.dhcp_agent1.host}, observeds)
  2026. def test_filter_hosts_with_network_access_multi_segments(self):
  2027. net = self.driver.create_network(
  2028. self.context,
  2029. {'network': {'name': 'net1',
  2030. mpnet.SEGMENTS: [
  2031. {pnet.NETWORK_TYPE: 'vlan',
  2032. pnet.PHYSICAL_NETWORK: 'physnet1',
  2033. pnet.SEGMENTATION_ID: 1},
  2034. {pnet.NETWORK_TYPE: 'vlan',
  2035. pnet.PHYSICAL_NETWORK: 'physnet2',
  2036. pnet.SEGMENTATION_ID: 2}],
  2037. 'tenant_id': 'tenant_one',
  2038. 'admin_state_up': True,
  2039. 'shared': True}})
  2040. expecteds = {self.dhcp_agent1.host, self.dhcp_agent2.host}
  2041. observeds = self.driver.filter_hosts_with_network_access(
  2042. self.context, net['id'], self.dhcp_hosts)
  2043. self.assertEqual(expecteds, observeds)
  2044. def test_filter_hosts_with_network_access_not_supported(self):
  2045. self.driver.mechanism_manager.host_filtering_supported = False
  2046. observeds = self.driver.filter_hosts_with_network_access(
  2047. self.context, 'fake_id', self.dhcp_hosts)
  2048. self.assertEqual(self.dhcp_hosts, observeds)
  2049. class DHCPOptsTestCase(test_dhcpopts.TestExtraDhcpOpt):
  2050. def setUp(self, plugin=None):
  2051. super(DHCPOptsTestCase, self).setUp(plugin=PLUGIN_NAME)
  2052. class Ml2PluginV2FaultyDriverTestCase(test_plugin.NeutronDbPluginV2TestCase):
  2053. def setUp(self):
  2054. # Enable the test mechanism driver to ensure that
  2055. # we can successfully call through to all mechanism
  2056. # driver apis.
  2057. cfg.CONF.set_override('mechanism_drivers',
  2058. ['test', 'logger'],
  2059. group='ml2')
  2060. super(Ml2PluginV2FaultyDriverTestCase, self).setUp(PLUGIN_NAME)
  2061. self.port_create_status = 'DOWN'
  2062. class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
  2063. def test_create_network_faulty(self):
  2064. err_msg = "Some errors"
  2065. with mock.patch.object(mech_test.TestMechanismDriver,
  2066. 'create_network_postcommit',
  2067. side_effect=(exc.InvalidInput(
  2068. error_message=err_msg))):
  2069. tenant_id = uuidutils.generate_uuid()
  2070. data = {'network': {'name': 'net1',
  2071. 'tenant_id': tenant_id}}
  2072. req = self.new_create_request('networks', data)
  2073. res = req.get_response(self.api)
  2074. self.assertEqual(400, res.status_int)
  2075. error = self.deserialize(self.fmt, res)
  2076. self.assertEqual('InvalidInput',
  2077. error['NeutronError']['type'])
  2078. # Check the client can see the root cause of error.
  2079. self.assertIn(err_msg, error['NeutronError']['message'])
  2080. query_params = "tenant_id=%s" % tenant_id
  2081. nets = self._list('networks', query_params=query_params)
  2082. self.assertFalse(nets['networks'])
  2083. def test_delete_network_faulty(self):
  2084. with mock.patch.object(mech_test.TestMechanismDriver,
  2085. 'delete_network_postcommit',
  2086. side_effect=ml2_exc.MechanismDriverError):
  2087. with mock.patch.object(mech_logger.LoggerMechanismDriver,
  2088. 'delete_network_postcommit') as dnp:
  2089. data = {'network': {'name': 'net1',
  2090. 'tenant_id': 'tenant_one'}}
  2091. network_req = self.new_create_request('networks', data)
  2092. network_res = network_req.get_response(self.api)
  2093. self.assertEqual(201, network_res.status_int)
  2094. network = self.deserialize(self.fmt, network_res)
  2095. net_id = network['network']['id']
  2096. req = self.new_delete_request('networks', net_id)
  2097. res = req.get_response(self.api)
  2098. self.assertEqual(204, res.status_int)
  2099. # Test if other mechanism driver was called
  2100. self.assertTrue(dnp.called)
  2101. self._show('networks', net_id,
  2102. expected_code=webob.exc.HTTPNotFound.code)
  2103. def test_update_network_faulty(self):
  2104. err_msg = "Some errors"
  2105. with mock.patch.object(mech_test.TestMechanismDriver,
  2106. 'update_network_postcommit',
  2107. side_effect=(exc.InvalidInput(
  2108. error_message=err_msg))):
  2109. with mock.patch.object(mech_logger.LoggerMechanismDriver,
  2110. 'update_network_postcommit') as unp:
  2111. data = {'network': {'name': 'net1',
  2112. 'tenant_id': 'tenant_one'}}
  2113. network_req = self.new_create_request('networks', data)
  2114. network_res = network_req.get_response(self.api)
  2115. self.assertEqual(201, network_res.status_int)
  2116. network = self.deserialize(self.fmt, network_res)
  2117. net_id = network['network']['id']
  2118. new_name = 'a_brand_new_name'
  2119. data = {'network': {'name': new_name}}
  2120. req = self.new_update_request('networks', data, net_id)
  2121. res = req.get_response(self.api)
  2122. self.assertEqual(400, res.status_int)
  2123. error = self.deserialize(self.fmt, res)
  2124. self.assertEqual('InvalidInput',
  2125. error['NeutronError']['type'])
  2126. # Check the client can see the root cause of error.
  2127. self.assertIn(err_msg, error['NeutronError']['message'])
  2128. # Test if other mechanism driver was called
  2129. self.assertTrue(unp.called)
  2130. net = self._show('networks', net_id)
  2131. self.assertEqual(new_name, net['network']['name'])
  2132. self._delete('networks', net_id)
  2133. def test_create_subnet_faulty(self):
  2134. err_msg = "Some errors"
  2135. with mock.patch.object(mech_test.TestMechanismDriver,
  2136. 'create_subnet_postcommit',
  2137. side_effect=(exc.InvalidInput(
  2138. error_message=err_msg))):
  2139. with self.network() as network:
  2140. net_id = network['network']['id']
  2141. data = {'subnet': {'network_id': net_id,
  2142. 'cidr': '10.0.20.0/24',
  2143. 'ip_version': '4',
  2144. 'name': 'subnet1',
  2145. 'tenant_id':
  2146. network['network']['tenant_id'],
  2147. 'gateway_ip': '10.0.20.1'}}
  2148. req = self.new_create_request('subnets', data)
  2149. res = req.get_response(self.api)
  2150. self.assertEqual(400, res.status_int)
  2151. error = self.deserialize(self.fmt, res)
  2152. self.assertEqual('InvalidInput',
  2153. error['NeutronError']['type'])
  2154. # Check the client can see the root cause of error.
  2155. self.assertIn(err_msg, error['NeutronError']['message'])
  2156. query_params = "network_id=%s" % net_id
  2157. subnets = self._list('subnets', query_params=query_params)
  2158. self.assertFalse(subnets['subnets'])
  2159. def test_delete_subnet_faulty(self):
  2160. with mock.patch.object(mech_test.TestMechanismDriver,
  2161. 'delete_subnet_postcommit',
  2162. side_effect=ml2_exc.MechanismDriverError):
  2163. with mock.patch.object(mech_logger.LoggerMechanismDriver,
  2164. 'delete_subnet_postcommit') as dsp:
  2165. with self.network() as network:
  2166. data = {'subnet': {'network_id':
  2167. network['network']['id'],
  2168. 'cidr': '10.0.20.0/24',
  2169. 'ip_version': '4',
  2170. 'name': 'subnet1',
  2171. 'tenant_id':
  2172. network['network']['tenant_id'],
  2173. 'gateway_ip': '10.0.20.1'}}
  2174. subnet_req = self.new_create_request('subnets', data)
  2175. subnet_res = subnet_req.get_response(self.api)
  2176. self.assertEqual(201, subnet_res.status_int)
  2177. subnet = self.deserialize(self.fmt, subnet_res)
  2178. subnet_id = subnet['subnet']['id']
  2179. req = self.new_delete_request('subnets', subnet_id)
  2180. res = req.get_response(self.api)
  2181. self.assertEqual(204, res.status_int)
  2182. # Test if other mechanism driver was called
  2183. self.assertTrue(dsp.called)
  2184. self._show('subnets', subnet_id,
  2185. expected_code=webob.exc.HTTPNotFound.code)
  2186. def test_update_subnet_faulty(self):
  2187. err_msg = "Some errors"
  2188. with mock.patch.object(mech_test.TestMechanismDriver,
  2189. 'update_subnet_postcommit',
  2190. side_effect=(exc.InvalidInput(
  2191. error_message=err_msg))):
  2192. with mock.patch.object(mech_logger.LoggerMechanismDriver,
  2193. 'update_subnet_postcommit') as usp:
  2194. with self.network() as network:
  2195. data = {'subnet': {'network_id':
  2196. network['network']['id'],
  2197. 'cidr': '10.0.20.0/24',
  2198. 'ip_version': '4',
  2199. 'name': 'subnet1',
  2200. 'tenant_id':
  2201. network['network']['tenant_id'],
  2202. 'gateway_ip': '10.0.20.1'}}
  2203. subnet_req = self.new_create_request('subnets', data)
  2204. subnet_res = subnet_req.get_response(self.api)
  2205. self.assertEqual(201, subnet_res.status_int)
  2206. subnet = self.deserialize(self.fmt, subnet_res)
  2207. subnet_id = subnet['subnet']['id']
  2208. new_name = 'a_brand_new_name'
  2209. data = {'subnet': {'name': new_name}}
  2210. req = self.new_update_request('subnets', data, subnet_id)
  2211. res = req.get_response(self.api)
  2212. self.assertEqual(400, res.status_int)
  2213. error = self.deserialize(self.fmt, res)
  2214. self.assertEqual('InvalidInput',
  2215. error['NeutronError']['type'])
  2216. # Check the client can see the root cause of error.
  2217. self.assertIn(err_msg, error['NeutronError']['message'])
  2218. # Test if other mechanism driver was called
  2219. self.assertTrue(usp.called)
  2220. subnet = self._show('subnets', subnet_id)
  2221. self.assertEqual(new_name, subnet['subnet']['name'])
  2222. self._delete('subnets', subnet['subnet']['id'])
  2223. def test_create_port_faulty(self):
  2224. err_msg = "Some errors"
  2225. with mock.patch.object(mech_test.TestMechanismDriver,
  2226. 'create_port_postcommit',
  2227. side_effect=(exc.InvalidInput(
  2228. error_message=err_msg))):
  2229. with self.network() as network:
  2230. net_id = network['network']['id']
  2231. data = {'port': {'network_id': net_id,
  2232. 'tenant_id':
  2233. network['network']['tenant_id'],
  2234. 'name': 'port1',
  2235. 'admin_state_up': 1,
  2236. 'fixed_ips': []}}
  2237. req = self.new_create_request('ports', data)
  2238. res = req.get_response(self.api)
  2239. self.assertEqual(400, res.status_int)
  2240. error = self.deserialize(self.fmt, res)
  2241. self.assertEqual('InvalidInput',
  2242. error['NeutronError']['type'])
  2243. # Check the client can see the root cause of error.
  2244. self.assertIn(err_msg, error['NeutronError']['message'])
  2245. query_params = "network_id=%s" % net_id
  2246. ports = self._list('ports', query_params=query_params)
  2247. self.assertFalse(ports['ports'])
  2248. def test_update_port_faulty(self):
  2249. with mock.patch.object(mech_test.TestMechanismDriver,
  2250. 'update_port_postcommit',
  2251. side_effect=ml2_exc.MechanismDriverError):
  2252. with mock.patch.object(mech_logger.LoggerMechanismDriver,
  2253. 'update_port_postcommit') as upp:
  2254. with self.network() as network:
  2255. data = {'port': {'network_id': network['network']['id'],
  2256. 'tenant_id':
  2257. network['network']['tenant_id'],
  2258. 'name': 'port1',
  2259. 'admin_state_up': 1,
  2260. 'fixed_ips': []}}
  2261. port_req = self.new_create_request('ports', data)
  2262. port_res = port_req.get_response(self.api)
  2263. self.assertEqual(201, port_res.status_int)
  2264. port = self.deserialize(self.fmt, port_res)
  2265. port_id = port['port']['id']
  2266. new_name = 'a_brand_new_name'
  2267. data = {'port': {'name': new_name}}
  2268. req = self.new_update_request('ports', data, port_id)
  2269. res = req.get_response(self.api)
  2270. self.assertEqual(200, res.status_int)
  2271. # Test if other mechanism driver was called
  2272. self.assertTrue(upp.called)
  2273. port = self._show('ports', port_id)
  2274. self.assertEqual(new_name, port['port']['name'])
  2275. self._delete('ports', port['port']['id'])
  2276. def test_update_distributed_router_interface_port(self):
  2277. """Test validate distributed router interface update succeeds."""
  2278. host_id = 'host'
  2279. binding = models.DistributedPortBinding(
  2280. port_id='port_id',
  2281. host=host_id,
  2282. router_id='old_router_id',
  2283. vif_type=portbindings.VIF_TYPE_OVS,
  2284. vnic_type=portbindings.VNIC_NORMAL,
  2285. status=constants.PORT_STATUS_DOWN)
  2286. with mock.patch.object(
  2287. mech_test.TestMechanismDriver,
  2288. 'update_port_postcommit',
  2289. side_effect=ml2_exc.MechanismDriverError) as port_post,\
  2290. mock.patch.object(
  2291. mech_test.TestMechanismDriver,
  2292. 'update_port_precommit') as port_pre,\
  2293. mock.patch.object(
  2294. ml2_db, 'get_distributed_port_bindings') as dist_bindings:
  2295. dist_bindings.return_value = [binding]
  2296. port_pre.return_value = True
  2297. with self.network() as network:
  2298. with self.subnet(network=network) as subnet:
  2299. subnet_id = subnet['subnet']['id']
  2300. data = {'port': {
  2301. 'network_id': network['network']['id'],
  2302. 'tenant_id':
  2303. network['network']['tenant_id'],
  2304. 'name': 'port1',
  2305. 'device_owner':
  2306. constants.DEVICE_OWNER_DVR_INTERFACE,
  2307. 'admin_state_up': 1,
  2308. 'fixed_ips':
  2309. [{'subnet_id': subnet_id}]}}
  2310. port_req = self.new_create_request('ports', data)
  2311. port_res = port_req.get_response(self.api)
  2312. self.assertEqual(201, port_res.status_int)
  2313. port = self.deserialize(self.fmt, port_res)
  2314. port_id = port['port']['id']
  2315. new_name = 'a_brand_new_name'
  2316. data = {'port': {'name': new_name}}
  2317. req = self.new_update_request('ports', data, port_id)
  2318. res = req.get_response(self.api)
  2319. self.assertEqual(200, res.status_int)
  2320. self.assertTrue(dist_bindings.called)
  2321. self.assertTrue(port_pre.called)
  2322. self.assertTrue(port_post.called)
  2323. port = self._show('ports', port_id)
  2324. self.assertEqual(new_name, port['port']['name'])
  2325. class TestML2PluggableIPAM(test_ipam.UseIpamMixin, TestMl2SubnetsV2):
  2326. def test_create_subnet_delete_subnet_call_ipam_driver(self):
  2327. driver = 'neutron.ipam.drivers.neutrondb_ipam.driver.NeutronDbPool'
  2328. gateway_ip = '10.0.0.1'
  2329. cidr = '10.0.0.0/24'
  2330. with mock.patch(driver) as driver_mock:
  2331. request = mock.Mock()
  2332. request.subnet_id = uuidutils.generate_uuid()
  2333. request.subnet_cidr = netaddr.IPNetwork(cidr)
  2334. request.allocation_pools = []
  2335. request.gateway_ip = netaddr.IPAddress(gateway_ip)
  2336. request.tenant_id = uuidutils.generate_uuid()
  2337. ipam_subnet = mock.Mock()
  2338. ipam_subnet.get_details.return_value = request
  2339. driver_mock().allocate_subnet.return_value = ipam_subnet
  2340. self._test_create_subnet(gateway_ip=gateway_ip, cidr=cidr)
  2341. driver_mock().allocate_subnet.assert_called_with(mock.ANY)
  2342. driver_mock().remove_subnet.assert_called_with(request.subnet_id)
  2343. def test_delete_subnet_deallocates_slaac_correctly(self):
  2344. driver = 'neutron.ipam.drivers.neutrondb_ipam.driver.NeutronDbPool'
  2345. with self.network() as network:
  2346. with self.subnet(network=network,
  2347. cidr='2001:100::0/64',
  2348. ip_version=6,
  2349. ipv6_ra_mode=constants.IPV6_SLAAC) as subnet:
  2350. with self.port(subnet=subnet) as port:
  2351. with mock.patch(driver) as driver_mock:
  2352. # Validate that deletion of SLAAC allocation happens
  2353. # via IPAM interface, i.e. ipam_subnet.deallocate is
  2354. # called prior to subnet deletiong from db.
  2355. self._delete('subnets', subnet['subnet']['id'])
  2356. dealloc = driver_mock().get_subnet().deallocate
  2357. dealloc.assert_called_with(
  2358. port['port']['fixed_ips'][0]['ip_address'])
  2359. driver_mock().remove_subnet.assert_called_with(
  2360. subnet['subnet']['id'])
  2361. class TestTransactionGuard(Ml2PluginV2TestCase):
  2362. def test_delete_network_guard(self):
  2363. plugin = directory.get_plugin()
  2364. ctx = context.get_admin_context()
  2365. with db_api.context_manager.writer.using(ctx):
  2366. with testtools.ExpectedException(RuntimeError):
  2367. plugin.delete_network(ctx, 'id')
  2368. def test_delete_subnet_guard(self):
  2369. plugin = directory.get_plugin()
  2370. ctx = context.get_admin_context()
  2371. with db_api.context_manager.writer.using(ctx):
  2372. with testtools.ExpectedException(RuntimeError):
  2373. plugin.delete_subnet(ctx, 'id')
  2374. class TestML2Segments(Ml2PluginV2TestCase):
  2375. def _reserve_segment(self, network, seg_id=None):
  2376. segment = {'id': 'fake_id',
  2377. 'network_id': network['network']['id'],
  2378. 'tenant_id': network['network']['tenant_id'],
  2379. driver_api.NETWORK_TYPE: 'vlan',
  2380. driver_api.PHYSICAL_NETWORK: self.physnet}
  2381. if seg_id:
  2382. segment[driver_api.SEGMENTATION_ID] = seg_id
  2383. self.driver._handle_segment_change(
  2384. mock.ANY, events.PRECOMMIT_CREATE, segments_plugin.Plugin(),
  2385. self.context, segment)
  2386. if seg_id:
  2387. # Assert it is not changed
  2388. self.assertEqual(seg_id, segment[driver_api.SEGMENTATION_ID])
  2389. else:
  2390. self.assertTrue(segment[driver_api.SEGMENTATION_ID] > 0)
  2391. return segment
  2392. def test_reserve_segment_success_with_partial_segment(self):
  2393. with self.network() as network:
  2394. self._reserve_segment(network)
  2395. def test_reserve_segment_fail_with_duplicate_param(self):
  2396. with self.network() as network:
  2397. self._reserve_segment(network, 10)
  2398. self.assertRaises(
  2399. exc.VlanIdInUse, self._reserve_segment, network, 10)
  2400. def test_create_network_mtu_on_precommit(self):
  2401. with mock.patch.object(mech_test.TestMechanismDriver,
  2402. 'create_network_precommit') as bmp:
  2403. with mock.patch.object(
  2404. self.driver, '_get_network_mtu') as mtu:
  2405. mtu.return_value = 1100
  2406. with self.network() as network:
  2407. self.assertIn('mtu', network['network'])
  2408. all_args = bmp.call_args_list
  2409. mech_context = all_args[0][0][0]
  2410. self.assertEqual(1100, mech_context.__dict__['_network']['mtu'])
  2411. def test_provider_info_update_network(self):
  2412. with self.network() as network:
  2413. network_id = network['network']['id']
  2414. plugin = directory.get_plugin()
  2415. updated_network = plugin.update_network(
  2416. self.context, network_id, {'network': {'name': 'test-net'}})
  2417. self.assertIn('provider:network_type', updated_network)
  2418. self.assertIn('provider:physical_network', updated_network)
  2419. self.assertIn('provider:segmentation_id', updated_network)
  2420. def test_reserve_segment_update_network_mtu(self):
  2421. with self.network() as network:
  2422. network_id = network['network']['id']
  2423. with mock.patch.object(
  2424. self.driver, '_get_network_mtu') as mtu:
  2425. mtu.return_value = 100
  2426. self._reserve_segment(network)
  2427. updated_network = self.driver.get_network(self.context,
  2428. network_id)
  2429. self.assertEqual(100, updated_network[driver_api.MTU])
  2430. mtu.return_value = 200
  2431. self._reserve_segment(network)
  2432. updated_network = self.driver.get_network(self.context,
  2433. network_id)
  2434. self.assertEqual(200, updated_network[driver_api.MTU])
  2435. def _test_nofity_mechanism_manager(self, event):
  2436. seg1 = {driver_api.NETWORK_TYPE: 'vlan',
  2437. driver_api.PHYSICAL_NETWORK: self.physnet,
  2438. driver_api.SEGMENTATION_ID: 1000}
  2439. seg2 = {driver_api.NETWORK_TYPE: 'vlan',
  2440. driver_api.PHYSICAL_NETWORK: self.physnet,
  2441. driver_api.SEGMENTATION_ID: 1001}
  2442. seg3 = {driver_api.NETWORK_TYPE: 'vlan',
  2443. driver_api.PHYSICAL_NETWORK: self.physnet,
  2444. driver_api.SEGMENTATION_ID: 1002}
  2445. with self.network() as network:
  2446. network = network['network']
  2447. for stale_seg in segments_db.get_network_segments(self.context,
  2448. network['id']):
  2449. segments_db.delete_network_segment(self.context, stale_seg['id'])
  2450. for seg in [seg1, seg2, seg3]:
  2451. seg['network_id'] = network['id']
  2452. segments_db.add_network_segment(self.context, network['id'], seg)
  2453. self.net_context = None
  2454. def record_network_context(net_context):
  2455. self.net_context = net_context
  2456. with mock.patch.object(managers.MechanismManager,
  2457. 'update_network_precommit',
  2458. side_effect=record_network_context):
  2459. self.driver._handle_segment_change(
  2460. mock.ANY, event, segments_plugin.Plugin(), self.context, seg1)
  2461. # Make sure the mechanism manager can get the right amount of
  2462. # segments of network
  2463. self.assertEqual(3, len(self.net_context.current[mpnet.SEGMENTS]))
  2464. def test_reserve_segment_nofity_mechanism_manager(self):
  2465. self._test_nofity_mechanism_manager(events.PRECOMMIT_CREATE)
  2466. def test_release_segment(self):
  2467. with self.network() as network:
  2468. segment = self._reserve_segment(network, 10)
  2469. segment['network_id'] = network['network']['id']
  2470. self.driver._handle_segment_change(
  2471. mock.ANY, events.PRECOMMIT_DELETE, mock.ANY,
  2472. self.context, segment)
  2473. # Check that the segment_id is not reserved
  2474. segment = self._reserve_segment(
  2475. network, segment[driver_api.SEGMENTATION_ID])
  2476. def test_release_segment_nofity_mechanism_manager(self):
  2477. self._test_nofity_mechanism_manager(events.PRECOMMIT_DELETE)
  2478. def test_prevent_delete_segment_with_tenant_port(self):
  2479. fake_owner_compute = constants.DEVICE_OWNER_COMPUTE_PREFIX + 'fake'
  2480. ml2_db.subscribe()
  2481. plugin = directory.get_plugin()
  2482. with self.port(device_owner=fake_owner_compute) as port:
  2483. # add writer here to make sure that the following operations are
  2484. # performed in the same session
  2485. with db_api.context_manager.writer.using(self.context):
  2486. binding = plugin._get_port(
  2487. self.context, port['port']['id']).port_binding
  2488. binding['host'] = 'host-ovs-no_filter'
  2489. mech_context = driver_context.PortContext(
  2490. plugin, self.context, port['port'],
  2491. plugin.get_network(self.context,
  2492. port['port']['network_id']),
  2493. binding, None)
  2494. plugin._bind_port_if_needed(mech_context)
  2495. segment = segments_db.get_network_segments(
  2496. self.context, port['port']['network_id'])[0]
  2497. segment['network_id'] = port['port']['network_id']
  2498. self.assertRaises(c_exc.CallbackFailure, registry.notify,
  2499. resources.SEGMENT, events.BEFORE_DELETE,
  2500. mock.ANY,
  2501. context=self.context, segment=segment)
  2502. exist_port = self._show('ports', port['port']['id'])
  2503. self.assertEqual(port['port']['id'], exist_port['port']['id'])