summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNader Lahouti <nlahouti@arista.com>2017-05-22 17:35:22 -0700
committerNader Lahouti <nader.lahouti@gmail.com>2017-06-05 23:52:28 +0000
commit29de9b8ff7b215ee07d34d2a58c806a9d896d227 (patch)
treea366fb65f0ca5fe4e8f0ed68d795fdee53615432
parent1652e6fbca4ed86eda58a765e0ac1d9c93419fd2 (diff)
Use only 'binding:host_id' to detect port migration
The existing code fails to detect a port migration if the port status is in 'DOWN' state. With this patch, detection of a port migration relies only on change in 'binding:host_id'. This patch also fixes failure of deleting a network due to orphan port in the arista_provisioned_vms database by deleting all entries from the table if they exist. Change-Id: I4faa8c9aafc39dce9e0773fcf2ff4836b86080dd (cherry picked from commit 30333342f2bd04e72ebc8c73829f416cda68add3)
Notes
Notes (review): Code-Review+2: mark mcclain <mark@mcclain.xyz> Workflow+1: mark mcclain <mark@mcclain.xyz> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Tue, 06 Jun 2017 14:57:56 +0000 Reviewed-on: https://review.openstack.org/471166 Project: openstack/networking-arista Branch: refs/heads/stable/newton
-rw-r--r--networking_arista/ml2/mechanism_arista.py35
-rw-r--r--networking_arista/tests/unit/ml2/test_mechanism_arista.py67
2 files changed, 27 insertions, 75 deletions
diff --git a/networking_arista/ml2/mechanism_arista.py b/networking_arista/ml2/mechanism_arista.py
index a377719..5be6e84 100644
--- a/networking_arista/ml2/mechanism_arista.py
+++ b/networking_arista/ml2/mechanism_arista.py
@@ -209,12 +209,10 @@ class AristaDriver(driver_api.MechanismDriver):
209 with self.eos_sync_lock: 209 with self.eos_sync_lock:
210 if db_lib.is_network_provisioned(tenant_id, network_id): 210 if db_lib.is_network_provisioned(tenant_id, network_id):
211 if db_lib.are_ports_attached_to_network(network_id): 211 if db_lib.are_ports_attached_to_network(network_id):
212 LOG.info(_LI('Network %s can not be deleted as it ' 212 db_lib.forget_all_ports_for_network(network_id)
213 'has ports attached to it'), network_id) 213 LOG.info(_LI('Deleting all ports on network %s'),
214 raise ml2_exc.MechanismDriverError( 214 network_id)
215 method='delete_network_precommit') 215 db_lib.forget_network_segment(tenant_id, network_id)
216 else:
217 db_lib.forget_network_segment(tenant_id, network_id)
218 216
219 def delete_network_postcommit(self, context): 217 def delete_network_postcommit(self, context):
220 """Send network delete request to Arista HW.""" 218 """Send network delete request to Arista HW."""
@@ -223,9 +221,9 @@ class AristaDriver(driver_api.MechanismDriver):
223 if not self.rpc.hpb_supported(): 221 if not self.rpc.hpb_supported():
224 # Hierarchical port binding is not supported by CVX, only 222 # Hierarchical port binding is not supported by CVX, only
225 # send the request if network type is VLAN. 223 # send the request if network type is VLAN.
226 if(segments and 224 if (segments and
227 segments[0][driver_api.NETWORK_TYPE] != p_const.TYPE_VLAN): 225 segments[0][driver_api.NETWORK_TYPE] != p_const.TYPE_VLAN):
228 # If networtk type is not VLAN, do nothing 226 # If network type is not VLAN, do nothing
229 return 227 return
230 # No need to pass segments info when calling delete_network as 228 # No need to pass segments info when calling delete_network as
231 # HPB is not supported. 229 # HPB is not supported.
@@ -451,15 +449,11 @@ class AristaDriver(driver_api.MechanismDriver):
451 """ 449 """
452 orig_port = context.original 450 orig_port = context.original
453 orig_host = context.original_host 451 orig_host = context.original_host
454 orig_status = context.original_status
455 new_status = context.status
456 new_host = context.host 452 new_host = context.host
457 new_port = context.current 453 new_port = context.current
458 port_id = orig_port['id'] 454 port_id = orig_port['id']
459 455
460 if (new_host != orig_host and 456 if new_host and orig_host and new_host != orig_host:
461 orig_status == n_const.PORT_STATUS_ACTIVE and
462 new_status == n_const.PORT_STATUS_DOWN):
463 LOG.debug("Handling port migration for: %s " % orig_port) 457 LOG.debug("Handling port migration for: %s " % orig_port)
464 network_id = orig_port['network_id'] 458 network_id = orig_port['network_id']
465 tenant_id = orig_port['tenant_id'] or INTERNAL_TENANT_ID 459 tenant_id = orig_port['tenant_id'] or INTERNAL_TENANT_ID
@@ -485,14 +479,9 @@ class AristaDriver(driver_api.MechanismDriver):
485 """ 479 """
486 orig_port = context.original 480 orig_port = context.original
487 orig_host = context.original_host 481 orig_host = context.original_host
488 orig_status = context.original_status
489 new_status = context.status
490 new_host = context.host 482 new_host = context.host
491 483
492 if (new_host != orig_host and 484 if new_host and orig_host and new_host != orig_host:
493 orig_status == n_const.PORT_STATUS_ACTIVE and
494 new_status == n_const.PORT_STATUS_DOWN):
495
496 self._try_to_release_dynamic_segment(context, migration=True) 485 self._try_to_release_dynamic_segment(context, migration=True)
497 486
498 # Handling migration case. 487 # Handling migration case.
@@ -504,7 +493,7 @@ class AristaDriver(driver_api.MechanismDriver):
504 # Ensure that we use tenant Id for the network owner 493 # Ensure that we use tenant Id for the network owner
505 tenant_id = self._network_owner_tenant(context, network_id, 494 tenant_id = self._network_owner_tenant(context, network_id,
506 tenant_id) 495 tenant_id)
507 for binding_level in context._original_binding_levels: 496 for binding_level in context._original_binding_levels or []:
508 if self._network_provisioned( 497 if self._network_provisioned(
509 tenant_id, network_id, 498 tenant_id, network_id,
510 segment_id=binding_level.segment_id): 499 segment_id=binding_level.segment_id):
@@ -769,7 +758,7 @@ class AristaDriver(driver_api.MechanismDriver):
769 port_id = port['id'] 758 port_id = port['id']
770 host_id = context.host 759 host_id = context.host
771 with self.eos_sync_lock: 760 with self.eos_sync_lock:
772 if db_lib.is_port_provisioned(port_id): 761 if db_lib.is_port_provisioned(port_id, host_id):
773 db_lib.forget_port(port_id, host_id) 762 db_lib.forget_port(port_id, host_id)
774 763
775 def delete_port_postcommit(self, context): 764 def delete_port_postcommit(self, context):
@@ -789,8 +778,8 @@ class AristaDriver(driver_api.MechanismDriver):
789 pretty_log("delete_port_postcommit:", port) 778 pretty_log("delete_port_postcommit:", port)
790 779
791 # If this port is the last one using dynamic segmentation id, 780 # If this port is the last one using dynamic segmentation id,
792 # and the segmentaion id was alloated by this driver, it needs 781 # and the segmentation id was allocated by this driver, it needs
793 # to be releaed. 782 # to be released.
794 self._try_to_release_dynamic_segment(context) 783 self._try_to_release_dynamic_segment(context)
795 784
796 with self.eos_sync_lock: 785 with self.eos_sync_lock:
diff --git a/networking_arista/tests/unit/ml2/test_mechanism_arista.py b/networking_arista/tests/unit/ml2/test_mechanism_arista.py
index 83971c7..881991b 100644
--- a/networking_arista/tests/unit/ml2/test_mechanism_arista.py
+++ b/networking_arista/tests/unit/ml2/test_mechanism_arista.py
@@ -456,7 +456,7 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
456 456
457 port_id = port_context.current['id'] 457 port_id = port_context.current['id']
458 expected_calls = [ 458 expected_calls = [
459 mock.call.is_port_provisioned(port_id), 459 mock.call.is_port_provisioned(port_id, port_context.host),
460 mock.call.forget_port(port_id, port_context.host), 460 mock.call.forget_port(port_id, port_context.host),
461 ] 461 ]
462 462
@@ -485,7 +485,7 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
485 485
486 port_id = port_context.current['id'] 486 port_id = port_context.current['id']
487 expected_calls += [ 487 expected_calls += [
488 mock.call.is_port_provisioned(port_id), 488 mock.call.is_port_provisioned(port_id, port_context.host),
489 mock.call.forget_port(port_id, port_context.host), 489 mock.call.forget_port(port_id, port_context.host),
490 ] 490 ]
491 491
@@ -619,7 +619,6 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
619 vm_id, 619 vm_id,
620 network_context) 620 network_context)
621 host_id = port_context.current['binding:host_id'] 621 host_id = port_context.current['binding:host_id']
622 port_context.original['binding:host_id'] = 'ubuntu0'
623 port_id = port_context.current['id'] 622 port_id = port_context.current['id']
624 623
625 network = {'tenant_id': tenant_id} 624 network = {'tenant_id': tenant_id}
@@ -661,7 +660,6 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
661 vm_id, 660 vm_id,
662 network_context) 661 network_context)
663 host_id = port_context.current['binding:host_id'] 662 host_id = port_context.current['binding:host_id']
664 port_context.original['binding:host_id'] = 'ubuntu0'
665 port_id = port_context.current['id'] 663 port_id = port_context.current['id']
666 664
667 # Force the check to return port found, but, network was not found 665 # Force the check to return port found, but, network was not found
@@ -682,8 +680,6 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
682 mock.call.is_network_provisioned(tenant_id, network_id, 680 mock.call.is_network_provisioned(tenant_id, network_id,
683 segmentation_id, segment_id), 681 segmentation_id, segment_id),
684 mock.call.is_port_provisioned(port_id, None), 682 mock.call.is_port_provisioned(port_id, None),
685 mock.call.update_port(vm_id, host_id, port_id,
686 network_id, tenant_id)
687 ] 683 ]
688 684
689 mechanism_arista.db_lib.assert_has_calls(expected_calls) 685 mechanism_arista.db_lib.assert_has_calls(expected_calls)
@@ -706,7 +702,6 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
706 # Port does not contain a tenant 702 # Port does not contain a tenant
707 port_context.current['tenant_id'] = None 703 port_context.current['tenant_id'] = None
708 host_id = port_context.current['binding:host_id'] 704 host_id = port_context.current['binding:host_id']
709 port_context.original['binding:host_id'] = 'ubuntu0'
710 port_id = port_context.current['id'] 705 port_id = port_context.current['id']
711 706
712 # Force the check to return port and network were found 707 # Force the check to return port and network were found
@@ -788,8 +783,7 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
788 device_id = port['device_id'] 783 device_id = port['device_id']
789 device_owner = port['device_owner'] 784 device_owner = port['device_owner']
790 host_id = port['binding:host_id'] 785 host_id = port['binding:host_id']
791 orig_host_id = 'ubuntu0' 786 orig_host_id = port_context.original_host
792 port_context.original['binding:host_id'] = orig_host_id
793 port_id = port['id'] 787 port_id = port['id']
794 port_name = port['name'] 788 port_name = port['name']
795 vnic_type = port['binding:vnic_type'] 789 vnic_type = port['binding:vnic_type']
@@ -811,16 +805,6 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
811 mock.call.create_network_segments(tenant_id, network_id, 805 mock.call.create_network_segments(tenant_id, network_id,
812 network_name, 806 network_name,
813 segments), 807 segments),
814 mock.call.is_network_provisioned(tenant_id, network_id, None,
815 None),
816 mock.call.unplug_port_from_network(device_id, 'compute',
817 orig_host_id, port_id,
818 network_id, tenant_id,
819 None, vnic_type,
820 switch_bindings=profile),
821 mock.call.remove_security_group(None, profile),
822 mock.call.num_nets_provisioned(tenant_id),
823 mock.call.num_vms_provisioned(tenant_id),
824 mock.call.plug_port_into_network(device_id, host_id, port_id, 808 mock.call.plug_port_into_network(device_id, host_id, port_id,
825 network_id, tenant_id, 809 network_id, tenant_id,
826 port_name, device_owner, None, 810 port_name, device_owner, None,
@@ -863,8 +847,7 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
863 device_id = port['device_id'] 847 device_id = port['device_id']
864 device_owner = port['device_owner'] 848 device_owner = port['device_owner']
865 host_id = port['binding:host_id'] 849 host_id = port['binding:host_id']
866 orig_host_id = 'ubuntu0' 850 orig_host_id = port_context.original_host
867 port_context.original['binding:host_id'] = orig_host_id
868 port_id = port['id'] 851 port_id = port['id']
869 port_name = port['name'] 852 port_name = port['name']
870 network_name = network_context.current['name'] 853 network_name = network_context.current['name']
@@ -881,17 +864,6 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
881 mock.call.create_network_segments(INTERNAL_TENANT_ID, network_id, 864 mock.call.create_network_segments(INTERNAL_TENANT_ID, network_id,
882 network_name, 865 network_name,
883 segments), 866 segments),
884 mock.call.is_network_provisioned(INTERNAL_TENANT_ID, network_id,
885 None, None),
886 mock.call.unplug_port_from_network(device_id, 'compute',
887 orig_host_id,
888 port_id, network_id,
889 INTERNAL_TENANT_ID,
890 None, vnic_type,
891 switch_bindings=profile),
892 mock.call.remove_security_group(None, profile),
893 mock.call.num_nets_provisioned(INTERNAL_TENANT_ID),
894 mock.call.num_vms_provisioned(INTERNAL_TENANT_ID),
895 mock.call.plug_port_into_network(device_id, host_id, port_id, 867 mock.call.plug_port_into_network(device_id, host_id, port_id,
896 network_id, INTERNAL_TENANT_ID, 868 network_id, INTERNAL_TENANT_ID,
897 port_name, device_owner, None, 869 port_name, device_owner, None,
@@ -1075,10 +1047,7 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
1075 self.drv.update_port_precommit(context) 1047 self.drv.update_port_precommit(context)
1076 1048
1077 expected_calls = [ 1049 expected_calls = [
1078 mock.call.is_network_provisioned(tenant_id, network_id, 1050 mock.call.is_port_provisioned(port_id, old_host),
1079 segmentation_id,
1080 segment_id),
1081 mock.call.is_port_provisioned(port_id, None),
1082 mock.call.update_port(new_device_id, 1051 mock.call.update_port(new_device_id,
1083 new_host, port_id, 1052 new_host, port_id,
1084 network_id, tenant_id) 1053 network_id, tenant_id)
@@ -1244,17 +1213,19 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
1244 context.current['binding:host_id'] = new_host 1213 context.current['binding:host_id'] = new_host
1245 context.current['status'] = 'DOWN' 1214 context.current['status'] = 'DOWN'
1246 1215
1216 physnet = dict(physnet='default')
1217 self.fake_rpc.get_physical_network.return_value = physnet
1218 context._original_binding_levels = context._binding_levels
1219
1247 mechanism_arista.db_lib.reset_mock() 1220 mechanism_arista.db_lib.reset_mock()
1248 self.drv.update_port_postcommit(context) 1221 self.drv.update_port_postcommit(context)
1249 1222
1250 expected_calls = [ 1223 expected_calls = []
1251 mock.call.is_port_provisioned(port_id, None), 1224 expected_calls.extend(
1252 mock.call.is_network_provisioned(tenant_id, network_id, 1225 mock.call.is_network_provisioned(tenant_id, network_id, None,
1253 None, None), 1226 binding_level.segment_id)
1254 mock.call.is_network_provisioned(tenant_id, network_id, 1227 for binding_level in context._original_binding_levels)
1255 segmentation_id, 1228 expected_calls += [
1256 None),
1257 mock.call.hpb_supported(),
1258 mock.call.is_network_provisioned(tenant_id, network_id, 1229 mock.call.is_network_provisioned(tenant_id, network_id,
1259 None, None), 1230 None, None),
1260 mock.call.unplug_port_from_network(reserved_device, 1231 mock.call.unplug_port_from_network(reserved_device,
@@ -1267,14 +1238,6 @@ class AristaDriverTestCase(testlib_api.SqlTestCase):
1267 mock.call.remove_security_group(None, profile), 1238 mock.call.remove_security_group(None, profile),
1268 mock.call.num_nets_provisioned(tenant_id), 1239 mock.call.num_nets_provisioned(tenant_id),
1269 mock.call.num_vms_provisioned(tenant_id), 1240 mock.call.num_vms_provisioned(tenant_id),
1270 mock.call.plug_port_into_network(new_device_id,
1271 new_host,
1272 port_id, network_id,
1273 tenant_id, port_name,
1274 n_const.DEVICE_OWNER_DHCP,
1275 None, None, vnic_type,
1276 segments=[],
1277 switch_bindings=profile),
1278 ] 1241 ]
1279 1242
1280 mechanism_arista.db_lib.assert_has_calls(expected_calls) 1243 mechanism_arista.db_lib.assert_has_calls(expected_calls)