summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Mooney <work@seanmooney.info>2018-10-23 17:14:58 +0100
committerLucas Alvares Gomes <lucasagomes@gmail.com>2018-11-21 13:51:04 +0000
commit9fc6b5d205b1ccf24541e64042af63bb993afd0e (patch)
tree573c842c8600546fd7399fb51c9ba8f7b55296a4
parent0a6a14de3cc7c0ebc283dbdb98940e59415aaef3 (diff)
Extend ml2 plugin to notify nova of port status
- This change modifies the ovn ml2 driver to notify nova on port status changes. - This will help enable faster migration when using ml2/ovn in the future by notifying nova once ovn has completed wireing up the interface. Closes-Bug: #1804407 Co-Authored-By: Lucas Alvares Gomes <lucasagomes@gmail.com> Change-Id: I450482c542f10c21f210be570df9ec7c9a617c94
Notes
Notes (review): Code-Review+2: Daniel Alvarez <dalvarez@redhat.com> Code-Review+1: sean mooney <work@seanmooney.info> Code-Review+1: Terry Wilson <twilson@redhat.com> Code-Review+2: Miguel Angel Ajo <mangelajo@redhat.com> Workflow+1: Miguel Angel Ajo <mangelajo@redhat.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Thu, 29 Nov 2018 22:06:18 +0000 Reviewed-on: https://review.openstack.org/612745 Project: openstack/networking-ovn Branch: refs/heads/master
-rw-r--r--networking_ovn/ml2/mech_driver.py44
-rw-r--r--networking_ovn/tests/unit/ml2/test_mech_driver.py52
2 files changed, 79 insertions, 17 deletions
diff --git a/networking_ovn/ml2/mech_driver.py b/networking_ovn/ml2/mech_driver.py
index 17b7d7a..cd26683 100644
--- a/networking_ovn/ml2/mech_driver.py
+++ b/networking_ovn/ml2/mech_driver.py
@@ -35,6 +35,7 @@ from oslo_utils import timeutils
35 35
36from neutron.common import utils as n_utils 36from neutron.common import utils as n_utils
37from neutron.db import provisioning_blocks 37from neutron.db import provisioning_blocks
38from neutron.plugins.ml2 import db as ml2_db
38from neutron.services.segments import db as segment_service_db 39from neutron.services.segments import db as segment_service_db
39 40
40from networking_ovn._i18n import _ 41from networking_ovn._i18n import _
@@ -394,7 +395,8 @@ class OVNMechanismDriver(api.MechanismDriver):
394 return 395 return
395 utils.validate_and_get_data_from_binding_profile(port) 396 utils.validate_and_get_data_from_binding_profile(port)
396 if self._is_port_provisioning_required(port, context.host): 397 if self._is_port_provisioning_required(port, context.host):
397 self._insert_port_provisioning_block(context._plugin_context, port) 398 self._insert_port_provisioning_block(context._plugin_context,
399 port['id'])
398 400
399 db_rev.create_initial_revision(port['id'], 401 db_rev.create_initial_revision(port['id'],
400 ovn_const.TYPE_PORTS, 402 ovn_const.TYPE_PORTS,
@@ -438,13 +440,12 @@ class OVNMechanismDriver(api.MechanismDriver):
438 440
439 return True 441 return True
440 442
441 def _insert_port_provisioning_block(self, context, port): 443 def _insert_port_provisioning_block(self, context, port_id):
442 # Insert a provisioning block to prevent the port from 444 # Insert a provisioning block to prevent the port from
443 # transitioning to active until OVN reports back that 445 # transitioning to active until OVN reports back that
444 # the port is up. 446 # the port is up.
445 provisioning_blocks.add_provisioning_component( 447 provisioning_blocks.add_provisioning_component(
446 context, 448 context, port_id, resources.PORT,
447 port['id'], resources.PORT,
448 provisioning_blocks.L2_AGENT_ENTITY 449 provisioning_blocks.L2_AGENT_ENTITY
449 ) 450 )
450 451
@@ -509,7 +510,8 @@ class OVNMechanismDriver(api.MechanismDriver):
509 utils.validate_and_get_data_from_binding_profile(port) 510 utils.validate_and_get_data_from_binding_profile(port)
510 if self._is_port_provisioning_required(port, context.host, 511 if self._is_port_provisioning_required(port, context.host,
511 context.original_host): 512 context.original_host):
512 self._insert_port_provisioning_block(context._plugin_context, port) 513 self._insert_port_provisioning_block(context._plugin_context,
514 port['id'])
513 515
514 if utils.is_lsp_router_port(port): 516 if utils.is_lsp_router_port(port):
515 # handle the case when an existing port is added to a 517 # handle the case when an existing port is added to a
@@ -772,12 +774,18 @@ class OVNMechanismDriver(api.MechanismDriver):
772 # becasue the router ports are unbind so, for OVN we are 774 # becasue the router ports are unbind so, for OVN we are
773 # forcing the status here. Maybe it's something that we can 775 # forcing the status here. Maybe it's something that we can
774 # change in core Neutron in the future. 776 # change in core Neutron in the future.
775 port = self._plugin.get_port(admin_context, port_id) 777 db_port = ml2_db.get_port(admin_context, port_id)
776 if port.get('device_owner') in (const.DEVICE_OWNER_ROUTER_INTF, 778 if not db_port:
777 const.DEVICE_OWNER_DVR_INTERFACE, 779 return
778 const.DEVICE_OWNER_ROUTER_HA_INTF): 780
781 if db_port.device_owner in (const.DEVICE_OWNER_ROUTER_INTF,
782 const.DEVICE_OWNER_DVR_INTERFACE,
783 const.DEVICE_OWNER_ROUTER_HA_INTF):
779 self._plugin.update_port_status(admin_context, port_id, 784 self._plugin.update_port_status(admin_context, port_id,
780 const.PORT_STATUS_ACTIVE) 785 const.PORT_STATUS_ACTIVE)
786 elif db_port.device_owner.startswith(
787 const.DEVICE_OWNER_COMPUTE_PREFIX):
788 self._plugin.nova_notifier.notify_port_active_direct(db_port)
781 except (os_db_exc.DBReferenceError, n_exc.PortNotFound): 789 except (os_db_exc.DBReferenceError, n_exc.PortNotFound):
782 LOG.debug('Port not found during OVN status up report: %s', 790 LOG.debug('Port not found during OVN status up report: %s',
783 port_id) 791 port_id)
@@ -792,11 +800,21 @@ class OVNMechanismDriver(api.MechanismDriver):
792 self._update_dnat_entry_if_needed(port_id, False) 800 self._update_dnat_entry_if_needed(port_id, False)
793 admin_context = n_context.get_admin_context() 801 admin_context = n_context.get_admin_context()
794 try: 802 try:
795 port = self._plugin.get_port(admin_context, port_id) 803 db_port = ml2_db.get_port(admin_context, port_id)
796 self._insert_port_provisioning_block(admin_context, port) 804 if not db_port:
797 self._plugin.update_port_status(admin_context, 805 return
798 port['id'], 806
807 self._insert_port_provisioning_block(admin_context, port_id)
808 self._plugin.update_port_status(admin_context, port_id,
799 const.PORT_STATUS_DOWN) 809 const.PORT_STATUS_DOWN)
810
811 if db_port.device_owner.startswith(
812 const.DEVICE_OWNER_COMPUTE_PREFIX):
813 self._plugin.nova_notifier.record_port_status_changed(
814 db_port, const.PORT_STATUS_ACTIVE, const.PORT_STATUS_DOWN,
815 None)
816 self._plugin.nova_notifier.send_port_status(
817 None, None, db_port)
800 except (os_db_exc.DBReferenceError, n_exc.PortNotFound): 818 except (os_db_exc.DBReferenceError, n_exc.PortNotFound):
801 LOG.debug("Port not found during OVN status down report: %s", 819 LOG.debug("Port not found during OVN status down report: %s",
802 port_id) 820 port_id)
diff --git a/networking_ovn/tests/unit/ml2/test_mech_driver.py b/networking_ovn/tests/unit/ml2/test_mech_driver.py
index 9ee6380..43e544b 100644
--- a/networking_ovn/tests/unit/ml2/test_mech_driver.py
+++ b/networking_ovn/tests/unit/ml2/test_mech_driver.py
@@ -693,11 +693,14 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
693 self.assertEqual( 693 self.assertEqual(
694 1, self.nb_ovn.update_address_set.call_count) 694 1, self.nb_ovn.update_address_set.call_count)
695 695
696 def test_set_port_status_up(self): 696 def _test_set_port_status_up(self, is_compute_port=False):
697 port_device_owner = 'compute:nova' if is_compute_port else ''
698 self.mech_driver._plugin.nova_notifier = mock.Mock()
697 with self.network(set_context=True, tenant_id='test') as net1, \ 699 with self.network(set_context=True, tenant_id='test') as net1, \
698 self.subnet(network=net1) as subnet1, \ 700 self.subnet(network=net1) as subnet1, \
699 self.port(subnet=subnet1, set_context=True, 701 self.port(subnet=subnet1, set_context=True,
700 tenant_id='test') as port1, \ 702 tenant_id='test',
703 device_owner=port_device_owner) as port1, \
701 mock.patch('neutron.db.provisioning_blocks.' 704 mock.patch('neutron.db.provisioning_blocks.'
702 'provisioning_complete') as pc, \ 705 'provisioning_complete') as pc, \
703 mock.patch.object( 706 mock.patch.object(
@@ -715,11 +718,30 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
715 upd_subport.assert_called_once_with(port1['port']['id']) 718 upd_subport.assert_called_once_with(port1['port']['id'])
716 ude.assert_called_once_with(port1['port']['id']) 719 ude.assert_called_once_with(port1['port']['id'])
717 720
718 def test_set_port_status_down(self): 721 # If the port does NOT bellong to compute, do not notify Nova
722 # about it's status changes
723 if not is_compute_port:
724 self.mech_driver._plugin.nova_notifier.\
725 notify_port_active_direct.assert_not_called()
726 else:
727 self.mech_driver._plugin.nova_notifier.\
728 notify_port_active_direct.assert_called_once_with(
729 mock.ANY)
730
731 def test_set_port_status_up(self):
732 self._test_set_port_status_up(is_compute_port=False)
733
734 def test_set_compute_port_status_up(self):
735 self._test_set_port_status_up(is_compute_port=True)
736
737 def _test_set_port_status_down(self, is_compute_port=False):
738 port_device_owner = 'compute:nova' if is_compute_port else ''
739 self.mech_driver._plugin.nova_notifier = mock.Mock()
719 with self.network(set_context=True, tenant_id='test') as net1, \ 740 with self.network(set_context=True, tenant_id='test') as net1, \
720 self.subnet(network=net1) as subnet1, \ 741 self.subnet(network=net1) as subnet1, \
721 self.port(subnet=subnet1, set_context=True, 742 self.port(subnet=subnet1, set_context=True,
722 tenant_id='test') as port1, \ 743 tenant_id='test',
744 device_owner=port_device_owner) as port1, \
723 mock.patch('neutron.db.provisioning_blocks.' 745 mock.patch('neutron.db.provisioning_blocks.'
724 'add_provisioning_component') as apc, \ 746 'add_provisioning_component') as apc, \
725 mock.patch.object(self.mech_driver, 747 mock.patch.object(self.mech_driver,
@@ -733,6 +755,28 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
733 ) 755 )
734 ude.assert_called_once_with(port1['port']['id'], False) 756 ude.assert_called_once_with(port1['port']['id'], False)
735 757
758 # If the port does NOT bellong to compute, do not notify Nova
759 # about it's status changes
760 if not is_compute_port:
761 self.mech_driver._plugin.nova_notifier.\
762 record_port_status_changed.assert_not_called()
763 self.mech_driver._plugin.nova_notifier.\
764 send_port_status.assert_not_called()
765 else:
766 self.mech_driver._plugin.nova_notifier.\
767 record_port_status_changed.assert_called_once_with(
768 mock.ANY, const.PORT_STATUS_ACTIVE,
769 const.PORT_STATUS_DOWN, None)
770 self.mech_driver._plugin.nova_notifier.\
771 send_port_status.assert_called_once_with(
772 None, None, mock.ANY)
773
774 def test_set_port_status_down(self):
775 self._test_set_port_status_down(is_compute_port=False)
776
777 def test_set_compute_port_status_down(self):
778 self._test_set_port_status_down(is_compute_port=True)
779
736 def test_set_port_status_down_not_found(self): 780 def test_set_port_status_down_not_found(self):
737 with mock.patch('neutron.db.provisioning_blocks.' 781 with mock.patch('neutron.db.provisioning_blocks.'
738 'add_provisioning_component') as apc, \ 782 'add_provisioning_component') as apc, \