Browse Source

Don't update existing port if no change

This allows external service pre-create a neutron port with
'binding:host_id' populated before passing the port to kuryr.
This is important because setting 'binding:host_id' is slow.
This blocks the docker daemon for serving other requests,
which blocks the whole system.
We want to have this field pre-populated so that the docker
daemon won't be blocked by this API call.

This commit also allows the 'device_owner' field to be
customized if users choose to pre-populate the 'binding:host_id'
field. In addition, this commit skips the API call to update the
neutron port if the 'binding:host_id' is pre-populated
and 'admin_state_up' and 'mac_address' fields are unchanged.

Closes-Bug: #1809306
Change-Id: I09c4a51410dffaec21ab0bb3db85df8c776c92e5
Hongbin Lu 3 months ago
parent
commit
5fb8275d12

+ 12
- 9
kuryr_libnetwork/port_driver/driver.py View File

@@ -129,26 +129,29 @@ class Driver(object):
129 129
                   python-neutronclient
130 130
         """
131 131
         try:
132
-            updated_port = {
133
-                'device_owner': lib_const.DEVICE_OWNER,
134
-                'binding:host_id': lib_utils.get_hostname(),
135
-                'admin_state_up': True,
136
-            }
132
+            updated_port = {}
133
+            hostname = lib_utils.get_hostname()
134
+            if port['binding:host_id'] != hostname:
135
+                updated_port['binding:host_id'] = hostname
136
+                updated_port['device_owner'] = lib_const.DEVICE_OWNER
137
+            if port['admin_state_up'] is not True:
138
+                updated_port['admin_state_up'] = True
137 139
             if not tags:
138 140
                 # rename the port if tagging is not supported
139 141
                 updated_port['name'] = libnet_utils.get_neutron_port_name(
140 142
                     endpoint_id)
141 143
             if not port.get('device_id'):
142 144
                 updated_port['device_id'] = endpoint_id
143
-            if interface_mac:
145
+            if interface_mac and port['mac_address'] != interface_mac:
144 146
                 updated_port['mac_address'] = interface_mac
145
-            response_port = app.neutron.update_port(port['id'],
146
-                                                    {'port': updated_port})
147
+            if updated_port:
148
+                port = app.neutron.update_port(port['id'],
149
+                                               {'port': updated_port})['port']
147 150
         except n_exceptions.NeutronClientException as ex:
148 151
             LOG.error("Error happened during updating a "
149 152
                       "Neutron port: %s", ex)
150 153
             raise
151
-        return response_port['port']
154
+        return port
152 155
 
153 156
     def __str__(self):
154 157
         return self.__class__.__name__

+ 7
- 2
kuryr_libnetwork/tests/unit/base.py View File

@@ -172,7 +172,9 @@ class TestKuryrBase(TestCase):
172 172
                        neutron_trunk_id=None,
173 173
                        tags=None,
174 174
                        name=None,
175
-                       binding_profile=None):
175
+                       binding_profile=None,
176
+                       binding_host=None,
177
+                       admin_state_up=True):
176 178
         # The following fake response is retrieved from the Neutron doc:
177 179
         #   http://developer.openstack.org/api-ref-networking-v2.html#createPort  # noqa
178 180
         if not name:
@@ -182,7 +184,7 @@ class TestKuryrBase(TestCase):
182 184
                 "status": neutron_port_status,
183 185
                 "name": name,
184 186
                 "allowed_address_pairs": [],
185
-                "admin_state_up": True,
187
+                "admin_state_up": admin_state_up,
186 188
                 "network_id": neutron_network_id,
187 189
                 "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
188 190
                 "device_owner": device_owner,
@@ -198,6 +200,9 @@ class TestKuryrBase(TestCase):
198 200
         if binding_profile is not None:
199 201
             fake_port['port']['binding:profile'] = binding_profile
200 202
 
203
+        if binding_host is not None:
204
+            fake_port['port']['binding:host_id'] = binding_host
205
+
201 206
         if neutron_subnet_v4_id:
202 207
             fake_port['port']['fixed_ips'].append({
203 208
                 "subnet_id": neutron_subnet_v4_id,

+ 30
- 3
kuryr_libnetwork/tests/unit/port_driver/drivers/test_veth.py View File

@@ -100,7 +100,8 @@ class TestVethDriver(base.TestKuryrBase):
100 100
             fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE,
101 101
             fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
102 102
             '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9',
103
-            fake_mac_address1)['port']
103
+            fake_mac_address1,
104
+            admin_state_up=False, binding_host='')['port']
104 105
         fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX])
105 106
         mock_get_port_name.return_value = fake_port_name
106 107
 
@@ -133,7 +134,8 @@ class TestVethDriver(base.TestKuryrBase):
133 134
             fake_endpoint_id, fake_neutron_net_id,
134 135
             fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE,
135 136
             fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
136
-            '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9')['port']
137
+            '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9',
138
+            admin_state_up=False, binding_host='')['port']
137 139
         fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX])
138 140
         mock_get_port_name.return_value = fake_port_name
139 141
 
@@ -167,7 +169,8 @@ class TestVethDriver(base.TestKuryrBase):
167 169
             fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE,
168 170
             fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
169 171
             '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9',
170
-            fake_mac_address1)['port']
172
+            fake_mac_address1,
173
+            admin_state_up=False, binding_host='')['port']
171 174
         fake_neutron_port.pop('device_id')
172 175
         fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX])
173 176
         mock_get_port_name.return_value = fake_port_name
@@ -188,3 +191,27 @@ class TestVethDriver(base.TestKuryrBase):
188 191
         }
189 192
         mock_update_port.assert_called_with(fake_neutron_port_id,
190 193
                                             expected_update_port)
194
+
195
+    @mock.patch('kuryr_libnetwork.app.neutron.update_port')
196
+    @mock.patch.object(libnet_utils, 'get_neutron_port_name')
197
+    def test_update_port_with_no_changes(self, mock_get_port_name,
198
+                                         mock_update_port):
199
+        fake_endpoint_id = lib_utils.get_hash()
200
+        fake_neutron_port_id = uuidutils.generate_uuid()
201
+        fake_neutron_net_id = uuidutils.generate_uuid()
202
+        fake_neutron_v4_subnet_id = uuidutils.generate_uuid()
203
+        fake_neutron_v6_subnet_id = uuidutils.generate_uuid()
204
+        fake_neutron_port = self._get_fake_port(
205
+            fake_endpoint_id, fake_neutron_net_id,
206
+            fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE,
207
+            fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
208
+            '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9',
209
+            binding_host=lib_utils.get_hostname())['port']
210
+        fake_port_name = '-'.join([fake_endpoint_id, lib_utils.PORT_POSTFIX])
211
+        mock_get_port_name.return_value = fake_port_name
212
+
213
+        veth_driver = veth.VethDriver()
214
+        veth_driver.update_port(fake_neutron_port, fake_endpoint_id, '')
215
+
216
+        mock_get_port_name.assert_called_with(fake_endpoint_id)
217
+        mock_update_port.assert_not_called()

+ 2
- 1
kuryr_libnetwork/tests/unit/port_driver/drivers/test_vlan.py View File

@@ -270,7 +270,8 @@ class TestVlanDriver(base.TestKuryrBase):
270 270
             fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE,
271 271
             fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
272 272
             '192.168.1.3', 'fe80::f816:3eff:fe1c:36a9',
273
-            fake_neutron_mac_address1)['port']
273
+            fake_neutron_mac_address1,
274
+            binding_host='', admin_state_up=False)['port']
274 275
         fake_vm_port = self._get_fake_port(
275 276
             fake_endpoint_id, fake_neutron_net_id,
276 277
             fake_vm_port_id, lib_const.PORT_STATUS_ACTIVE,

Loading…
Cancel
Save