diff --git a/kuryr_libnetwork/port_driver/driver.py b/kuryr_libnetwork/port_driver/driver.py index 52ecb1d4..a2a7a11a 100644 --- a/kuryr_libnetwork/port_driver/driver.py +++ b/kuryr_libnetwork/port_driver/driver.py @@ -129,26 +129,29 @@ class Driver(object): python-neutronclient """ try: - updated_port = { - 'device_owner': lib_const.DEVICE_OWNER, - 'binding:host_id': lib_utils.get_hostname(), - 'admin_state_up': True, - } + updated_port = {} + hostname = lib_utils.get_hostname() + if port['binding:host_id'] != hostname: + updated_port['binding:host_id'] = hostname + updated_port['device_owner'] = lib_const.DEVICE_OWNER + if port['admin_state_up'] is not True: + updated_port['admin_state_up'] = True if not tags: # rename the port if tagging is not supported updated_port['name'] = libnet_utils.get_neutron_port_name( endpoint_id) if not port.get('device_id'): updated_port['device_id'] = endpoint_id - if interface_mac: + if interface_mac and port['mac_address'] != interface_mac: updated_port['mac_address'] = interface_mac - response_port = app.neutron.update_port(port['id'], - {'port': updated_port}) + if updated_port: + port = app.neutron.update_port(port['id'], + {'port': updated_port})['port'] except n_exceptions.NeutronClientException as ex: LOG.error("Error happened during updating a " "Neutron port: %s", ex) raise - return response_port['port'] + return port def __str__(self): return self.__class__.__name__ diff --git a/kuryr_libnetwork/tests/unit/base.py b/kuryr_libnetwork/tests/unit/base.py index 26391c59..f771fd25 100644 --- a/kuryr_libnetwork/tests/unit/base.py +++ b/kuryr_libnetwork/tests/unit/base.py @@ -172,7 +172,9 @@ class TestKuryrBase(TestCase): neutron_trunk_id=None, tags=None, name=None, - binding_profile=None): + binding_profile=None, + binding_host=None, + admin_state_up=True): # The following fake response is retrieved from the Neutron doc: # http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa if not name: @@ -182,7 +184,7 @@ class TestKuryrBase(TestCase): "status": neutron_port_status, "name": name, "allowed_address_pairs": [], - "admin_state_up": True, + "admin_state_up": admin_state_up, "network_id": neutron_network_id, "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", "device_owner": device_owner, @@ -198,6 +200,9 @@ class TestKuryrBase(TestCase): if binding_profile is not None: fake_port['port']['binding:profile'] = binding_profile + if binding_host is not None: + fake_port['port']['binding:host_id'] = binding_host + if neutron_subnet_v4_id: fake_port['port']['fixed_ips'].append({ "subnet_id": neutron_subnet_v4_id, diff --git a/kuryr_libnetwork/tests/unit/port_driver/drivers/test_veth.py b/kuryr_libnetwork/tests/unit/port_driver/drivers/test_veth.py index 348bc7dc..cd7973c3 100644 --- a/kuryr_libnetwork/tests/unit/port_driver/drivers/test_veth.py +++ b/kuryr_libnetwork/tests/unit/port_driver/drivers/test_veth.py @@ -100,7 +100,8 @@ class TestVethDriver(base.TestKuryrBase): fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE, fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id, '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9', - fake_mac_address1)['port'] + fake_mac_address1, + admin_state_up=False, binding_host='')['port'] fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX]) mock_get_port_name.return_value = fake_port_name @@ -133,7 +134,8 @@ class TestVethDriver(base.TestKuryrBase): fake_endpoint_id, fake_neutron_net_id, fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE, fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id, - '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9')['port'] + '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9', + admin_state_up=False, binding_host='')['port'] fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX]) mock_get_port_name.return_value = fake_port_name @@ -167,7 +169,8 @@ class TestVethDriver(base.TestKuryrBase): fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE, fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id, '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9', - fake_mac_address1)['port'] + fake_mac_address1, + admin_state_up=False, binding_host='')['port'] fake_neutron_port.pop('device_id') fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX]) mock_get_port_name.return_value = fake_port_name @@ -188,3 +191,27 @@ class TestVethDriver(base.TestKuryrBase): } mock_update_port.assert_called_with(fake_neutron_port_id, expected_update_port) + + @mock.patch('kuryr_libnetwork.app.neutron.update_port') + @mock.patch.object(libnet_utils, 'get_neutron_port_name') + def test_update_port_with_no_changes(self, mock_get_port_name, + mock_update_port): + fake_endpoint_id = lib_utils.get_hash() + fake_neutron_port_id = uuidutils.generate_uuid() + fake_neutron_net_id = uuidutils.generate_uuid() + fake_neutron_v4_subnet_id = uuidutils.generate_uuid() + fake_neutron_v6_subnet_id = uuidutils.generate_uuid() + fake_neutron_port = self._get_fake_port( + fake_endpoint_id, fake_neutron_net_id, + fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE, + fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id, + '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9', + binding_host=lib_utils.get_hostname())['port'] + fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX]) + mock_get_port_name.return_value = fake_port_name + + veth_driver = veth.VethDriver() + veth_driver.update_port(fake_neutron_port, fake_endpoint_id, '') + + mock_get_port_name.assert_called_with(fake_endpoint_id) + mock_update_port.assert_not_called() diff --git a/kuryr_libnetwork/tests/unit/port_driver/drivers/test_vlan.py b/kuryr_libnetwork/tests/unit/port_driver/drivers/test_vlan.py index bd724ed0..ac4b9a30 100644 --- a/kuryr_libnetwork/tests/unit/port_driver/drivers/test_vlan.py +++ b/kuryr_libnetwork/tests/unit/port_driver/drivers/test_vlan.py @@ -270,7 +270,8 @@ class TestVlanDriver(base.TestKuryrBase): fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE, fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id, '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9', - fake_neutron_mac_address1)['port'] + fake_neutron_mac_address1, + binding_host='', admin_state_up=False)['port'] fake_vm_port = self._get_fake_port( fake_endpoint_id, fake_neutron_net_id, fake_vm_port_id, lib_const.PORT_STATUS_ACTIVE,