Browse Source

Pools support with Network Policies

This patch adapts the pools support to the use of Network Policies.
Unlike with the other drivers, when Network Policies are applied the
pods' ports changes their security groups while being used. That means
their original pool will not fit them anymore with the next two
consequences:
1.- Ports will have their original SG reapplied when pods are deleted,
with the consequent performance impact do to increasing the number of
calls to neutron
2.- Original pools may become useless, as different SGs are being used,
therefore wasting neutron ports

To accomodate for network policies, this patch removes the SG ids from
the pool key, merging all the pools with same network/project/host ids
but with different security groups into the same pool. This will not
change the behavior of the other drivers as there was a unique pool per
network/project/host ids already, i.e., the same SG ids were being used.
However, this will helps to avoid problem 1) as it is no longer
re-applying the SG, but simply putting the port back into its current
pool. And it will fix problem 2) as it will pick a port for an existing
pool that matches network/project/host ids. First it will search for one
with already matching SGs, and if not found, it will recycle one of the
others by reapplying the needed SGs (note it picks a port from one of
the pools that are less frequently used -- assumes they may belong to
a deleted NP that it is not needed anymore, thus removing the port
wastage problem)

Partially Implements: blueprint k8s-network-policies
Change-Id: I2c1e47fd5112c64b8e9984e5ac5d8572d91ac202
Luis Tomas Bolivar 2 months ago
parent
commit
e8c418c196

+ 149
- 68
kuryr_kubernetes/controller/drivers/vif_pool.py View File

@@ -155,23 +155,25 @@ class BaseVIFPool(base.VIFPoolDriver):
155 155
     def update_vif_sgs(self, pod, sgs):
156 156
         self._drv_vif.update_vif_sgs(pod, sgs)
157 157
 
158
-    def _get_pool_size(self, pool_key=None):
159
-        return len(self._available_ports_pools.get(pool_key, []))
158
+    def _get_pool_size(self, pool_key):
159
+        pool = self._available_ports_pools.get(pool_key, {})
160
+        pool_members = []
161
+        for port_list in pool.values():
162
+            pool_members.extend(port_list)
163
+        return len(pool_members)
160 164
 
161 165
     def _get_host_addr(self, pod):
162 166
         return pod['status']['hostIP']
163 167
 
164
-    def _get_pool_key(self, host, project_id, security_groups, net_id=None,
165
-                      subnets=None):
168
+    def _get_pool_key(self, host, project_id, net_id=None, subnets=None):
166 169
         if not net_id and subnets:
167 170
             net_obj = list(subnets.values())[0]
168 171
             net_id = net_obj.id
169
-        pool_key = (host, project_id, tuple(sorted(security_groups)),
170
-                    net_id)
172
+        pool_key = (host, project_id, net_id)
171 173
         return pool_key
172 174
 
173 175
     def _get_pool_key_net(self, pool_key):
174
-        return pool_key[3]
176
+        return pool_key[2]
175 177
 
176 178
     def request_vif(self, pod, project_id, subnets, security_groups):
177 179
         try:
@@ -179,33 +181,37 @@ class BaseVIFPool(base.VIFPoolDriver):
179 181
         except KeyError:
180 182
             LOG.warning("Pod has not been scheduled yet.")
181 183
             raise
182
-        pool_key = self._get_pool_key(host_addr, project_id, security_groups,
183
-                                      None, subnets)
184
+        pool_key = self._get_pool_key(host_addr, project_id, None, subnets)
184 185
 
185 186
         try:
186
-            return self._get_port_from_pool(pool_key, pod, subnets)
187
+            return self._get_port_from_pool(pool_key, pod, subnets,
188
+                                            tuple(sorted(security_groups)))
187 189
         except exceptions.ResourceNotReady:
188 190
             LOG.warning("Ports pool does not have available ports!")
189
-            eventlet.spawn(self._populate_pool, pool_key, pod, subnets)
191
+            eventlet.spawn(self._populate_pool, pool_key, pod, subnets,
192
+                           tuple(sorted(security_groups)))
190 193
             raise
191 194
 
192
-    def _get_port_from_pool(self, pool_key, pod, subnets):
195
+    def _get_port_from_pool(self, pool_key, pod, subnets, security_groups):
193 196
         raise NotImplementedError()
194 197
 
195
-    def _populate_pool(self, pool_key, pod, subnets):
198
+    def _populate_pool(self, pool_key, pod, subnets, security_groups):
196 199
         # REVISIT(ltomasbo): Drop the subnets parameter and get the information
197 200
         # from the pool_key, which will be required when multi-network is
198 201
         # supported
199 202
         now = time.time()
200
-        try:
201
-            if (now - oslo_cfg.CONF.vif_pool.ports_pool_update_frequency <
202
-                    self._last_update.get(pool_key, 0)):
203
-                LOG.info("Not enough time since the last pool update")
203
+        pool_updates = self._last_update.get(pool_key)
204
+        if pool_updates:
205
+            last_update = pool_updates.get(security_groups, 0)
206
+            try:
207
+                if (now - oslo_cfg.CONF.vif_pool.ports_pool_update_frequency <
208
+                        last_update):
209
+                    LOG.info("Not enough time since the last pool update")
210
+                    return
211
+            except AttributeError:
212
+                LOG.info("Kuryr-controller not yet ready to populate pools")
204 213
                 return
205
-        except AttributeError:
206
-            LOG.info("Kuryr-controller not yet ready to populate pools")
207
-            return
208
-        self._last_update[pool_key] = now
214
+        self._last_update[pool_key] = {security_groups: now}
209 215
 
210 216
         pool_size = self._get_pool_size(pool_key)
211 217
         if pool_size < oslo_cfg.CONF.vif_pool.ports_pool_min:
@@ -215,18 +221,19 @@ class BaseVIFPool(base.VIFPoolDriver):
215 221
                 pod=pod,
216 222
                 project_id=pool_key[1],
217 223
                 subnets=subnets,
218
-                security_groups=list(pool_key[2]),
224
+                security_groups=security_groups,
219 225
                 num_ports=num_ports)
220 226
             for vif in vifs:
221 227
                 self._existing_vifs[vif.id] = vif
222
-                self._available_ports_pools.setdefault(pool_key,
223
-                                                       []).append(vif.id)
228
+                self._available_ports_pools.setdefault(
229
+                    pool_key, {}).setdefault(
230
+                        security_groups, []).append(vif.id)
224 231
 
225 232
     def release_vif(self, pod, vif, project_id, security_groups):
226 233
         host_addr = self._get_host_addr(pod)
227 234
 
228
-        pool_key = self._get_pool_key(host_addr, project_id, security_groups,
229
-                                      vif.network.id, None)
235
+        pool_key = self._get_pool_key(host_addr, project_id, vif.network.id,
236
+                                      None)
230 237
 
231 238
         try:
232 239
             if not self._existing_vifs.get(vif.id):
@@ -288,12 +295,10 @@ class BaseVIFPool(base.VIFPoolDriver):
288 295
     @lockutils.synchronized('return_to_pool_baremetal')
289 296
     @lockutils.synchronized('return_to_pool_nested')
290 297
     def sync_pools(self):
291
-        self._available_ports_pools = collections.defaultdict(
292
-            collections.deque)
293
-        self._existing_vifs = collections.defaultdict(collections.defaultdict)
294
-        self._recyclable_ports = collections.defaultdict(
295
-            collections.defaultdict)
296
-        self._last_update = collections.defaultdict(collections.defaultdict)
298
+        self._available_ports_pools = collections.defaultdict()
299
+        self._existing_vifs = collections.defaultdict()
300
+        self._recyclable_ports = collections.defaultdict()
301
+        self._last_update = collections.defaultdict()
297 302
         # NOTE(ltomasbo): Ensure previously created ports are recovered into
298 303
         # their respective pools
299 304
         self._recover_precreated_ports()
@@ -365,11 +370,45 @@ class NeutronVIFPool(BaseVIFPool):
365 370
     def _get_host_addr(self, pod):
366 371
         return pod['spec']['nodeName']
367 372
 
368
-    def _get_port_from_pool(self, pool_key, pod, subnets):
373
+    def _get_port_from_pool(self, pool_key, pod, subnets, security_groups):
369 374
         try:
370
-            port_id = self._available_ports_pools[pool_key].pop()
371
-        except (IndexError, AttributeError):
375
+            pool_ports = self._available_ports_pools[pool_key]
376
+        except (KeyError, AttributeError):
372 377
             raise exceptions.ResourceNotReady(pod)
378
+        try:
379
+            port_id = pool_ports[security_groups].pop()
380
+        except (KeyError, IndexError):
381
+            # Get another port from the pool and update the SG to the
382
+            # appropriate one. It uses a port from the group that was updated
383
+            # longer ago
384
+            pool_updates = self._last_update.get(pool_key, {})
385
+            if not pool_updates:
386
+                # No pools update info. Selecting a random one
387
+                for sg_group, ports in pool_ports.items():
388
+                    if len(ports) > 0:
389
+                        port_id = pool_ports[sg_group].pop()
390
+                        break
391
+                else:
392
+                    raise exceptions.ResourceNotReady(pod)
393
+            else:
394
+                min_date = -1
395
+                for sg_group, date in pool_updates.items():
396
+                    if pool_ports.get(sg_group):
397
+                        if min_date == -1 or date < min_date:
398
+                            min_date = date
399
+                            min_sg_group = sg_group
400
+                if min_date == -1:
401
+                    # pool is empty, no port to reuse
402
+                    raise exceptions.ResourceNotReady(pod)
403
+                port_id = pool_ports[min_sg_group].pop()
404
+            neutron = clients.get_neutron_client()
405
+            neutron.update_port(
406
+                port_id,
407
+                {
408
+                    "port": {
409
+                        'security_groups': list(security_groups)
410
+                    }
411
+                })
373 412
         if config.CONF.kubernetes.port_debug:
374 413
             neutron = clients.get_neutron_client()
375 414
             neutron.update_port(
@@ -383,7 +422,8 @@ class NeutronVIFPool(BaseVIFPool):
383 422
         # check if the pool needs to be populated
384 423
         if (self._get_pool_size(pool_key) <
385 424
                 oslo_cfg.CONF.vif_pool.ports_pool_min):
386
-            eventlet.spawn(self._populate_pool, pool_key, pod, subnets)
425
+            eventlet.spawn(self._populate_pool, pool_key, pod, subnets,
426
+                           security_groups)
387 427
         return self._existing_vifs[port_id]
388 428
 
389 429
     def _return_ports_to_pool(self):
@@ -414,7 +454,8 @@ class NeutronVIFPool(BaseVIFPool):
414 454
                 device_owner=kl_const.DEVICE_OWNER)
415 455
             for port in kuryr_ports:
416 456
                 if port['id'] in self._recyclable_ports:
417
-                    sg_current[port['id']] = port['security_groups']
457
+                    sg_current[port['id']] = tuple(sorted(
458
+                        port['security_groups']))
418 459
 
419 460
         for port_id, pool_key in self._recyclable_ports.copy().items():
420 461
             if (not oslo_cfg.CONF.vif_pool.ports_pool_max or
@@ -423,25 +464,24 @@ class NeutronVIFPool(BaseVIFPool):
423 464
                 port_name = (constants.KURYR_PORT_NAME
424 465
                              if config.CONF.kubernetes.port_debug
425 466
                              else '')
426
-                if (config.CONF.kubernetes.port_debug or
427
-                        list(pool_key[2]) != sg_current.get(port_id)):
467
+                if config.CONF.kubernetes.port_debug:
428 468
                     try:
429 469
                         neutron.update_port(
430 470
                             port_id,
431 471
                             {
432 472
                                 "port": {
433 473
                                     'name': port_name,
434
-                                    'device_id': '',
435
-                                    'security_groups': list(pool_key[2])
474
+                                    'device_id': ''
436 475
                                 }
437 476
                             })
438 477
                     except n_exc.NeutronClientException:
439
-                        LOG.warning("Error preparing port %s to be "
478
+                        LOG.warning("Error changing name for port %s to be "
440 479
                                     "reused, put back on the cleanable "
441 480
                                     "pool.", port_id)
442 481
                         continue
443 482
                 self._available_ports_pools.setdefault(
444
-                    pool_key, []).append(port_id)
483
+                    pool_key, {}).setdefault(
484
+                        sg_current.get(port_id), []).append(port_id)
445 485
             else:
446 486
                 try:
447 487
                     del self._existing_vifs[port_id]
@@ -490,12 +530,13 @@ class NeutronVIFPool(BaseVIFPool):
490 530
             net_obj = subnet[subnet_id]
491 531
             pool_key = self._get_pool_key(port_host,
492 532
                                           port['project_id'],
493
-                                          port['security_groups'],
494 533
                                           net_obj.id, None)
495 534
 
496 535
             self._existing_vifs[port['id']] = vif
497 536
             self._available_ports_pools.setdefault(
498
-                pool_key, []).append(port['id'])
537
+                pool_key, {}).setdefault(
538
+                    tuple(sorted(port['security_groups'])), []).append(
539
+                        port['id'])
499 540
 
500 541
         LOG.info("PORTS POOL: pools updated with pre-created ports")
501 542
         self._create_healthcheck_file()
@@ -512,10 +553,13 @@ class NeutronVIFPool(BaseVIFPool):
512 553
         # on the available_ports_pools dict. The next call forces it to be on
513 554
         # that dict before cleaning it up
514 555
         self._trigger_return_to_pool()
515
-        for pool_key, ports_id in self._available_ports_pools.items():
556
+        for pool_key, ports in self._available_ports_pools.items():
516 557
             if self._get_pool_key_net(pool_key) != net_id:
517 558
                 continue
518 559
             self._available_ports_pools[pool_key] = []
560
+            ports_id = []
561
+            for sg_ports in ports.values():
562
+                ports_id.extend(sg_ports)
519 563
             for port_id in ports_id:
520 564
                 try:
521 565
                     del self._existing_vifs[port_id]
@@ -548,11 +592,45 @@ class NestedVIFPool(BaseVIFPool):
548 592
     def set_vif_driver(self, driver):
549 593
         self._drv_vif = driver
550 594
 
551
-    def _get_port_from_pool(self, pool_key, pod, subnets):
595
+    def _get_port_from_pool(self, pool_key, pod, subnets, security_groups):
552 596
         try:
553
-            port_id = self._available_ports_pools[pool_key].pop()
554
-        except (IndexError, AttributeError):
597
+            pool_ports = self._available_ports_pools[pool_key]
598
+        except (KeyError, AttributeError):
555 599
             raise exceptions.ResourceNotReady(pod)
600
+        try:
601
+            port_id = pool_ports[security_groups].pop()
602
+        except (KeyError, IndexError):
603
+            # Get another port from the pool and update the SG to the
604
+            # appropriate one. It uses a port from the group that was updated
605
+            # longer ago
606
+            pool_updates = self._last_update.get(pool_key, {})
607
+            if not pool_updates:
608
+                # No pools update info. Selecting a random one
609
+                for sg_group, ports in pool_ports.items():
610
+                    if len(ports) > 0:
611
+                        port_id = pool_ports[sg_group].pop()
612
+                        break
613
+                else:
614
+                    raise exceptions.ResourceNotReady(pod)
615
+            else:
616
+                min_date = -1
617
+                for sg_group, date in pool_updates.items():
618
+                    if pool_ports.get(sg_group):
619
+                        if min_date == -1 or date < min_date:
620
+                            min_date = date
621
+                            min_sg_group = sg_group
622
+                if min_date == -1:
623
+                    # pool is empty, no port to reuse
624
+                    raise exceptions.ResourceNotReady(pod)
625
+                port_id = pool_ports[min_sg_group].pop()
626
+            neutron = clients.get_neutron_client()
627
+            neutron.update_port(
628
+                port_id,
629
+                {
630
+                    "port": {
631
+                        'security_groups': list(security_groups)
632
+                    }
633
+                })
556 634
         if config.CONF.kubernetes.port_debug:
557 635
             neutron = clients.get_neutron_client()
558 636
             neutron.update_port(
@@ -565,7 +643,8 @@ class NestedVIFPool(BaseVIFPool):
565 643
         # check if the pool needs to be populated
566 644
         if (self._get_pool_size(pool_key) <
567 645
                 oslo_cfg.CONF.vif_pool.ports_pool_min):
568
-            eventlet.spawn(self._populate_pool, pool_key, pod, subnets)
646
+            eventlet.spawn(self._populate_pool, pool_key, pod, subnets,
647
+                           security_groups)
569 648
         return self._existing_vifs[port_id]
570 649
 
571 650
     def _return_ports_to_pool(self):
@@ -596,7 +675,8 @@ class NestedVIFPool(BaseVIFPool):
596 675
                 device_owner=['trunk:subport', kl_const.DEVICE_OWNER])
597 676
             for subport in kuryr_subports:
598 677
                 if subport['id'] in self._recyclable_ports:
599
-                    sg_current[subport['id']] = subport['security_groups']
678
+                    sg_current[subport['id']] = tuple(sorted(
679
+                        subport['security_groups']))
600 680
 
601 681
         for port_id, pool_key in self._recyclable_ports.copy().items():
602 682
             if (not oslo_cfg.CONF.vif_pool.ports_pool_max or
@@ -605,24 +685,23 @@ class NestedVIFPool(BaseVIFPool):
605 685
                 port_name = (constants.KURYR_PORT_NAME
606 686
                              if config.CONF.kubernetes.port_debug
607 687
                              else '')
608
-                if (config.CONF.kubernetes.port_debug or
609
-                        list(pool_key[2]) != sg_current.get(port_id)):
688
+                if config.CONF.kubernetes.port_debug:
610 689
                     try:
611 690
                         neutron.update_port(
612 691
                             port_id,
613 692
                             {
614 693
                                 "port": {
615 694
                                     'name': port_name,
616
-                                    'security_groups': list(pool_key[2])
617 695
                                 }
618 696
                             })
619 697
                     except n_exc.NeutronClientException:
620
-                        LOG.warning("Error preparing port %s to be "
698
+                        LOG.warning("Error changing name for port %s to be "
621 699
                                     "reused, put back on the cleanable "
622 700
                                     "pool.", port_id)
623 701
                         continue
624 702
                 self._available_ports_pools.setdefault(
625
-                    pool_key, []).append(port_id)
703
+                    pool_key, {}).setdefault(
704
+                        sg_current.get(port_id), []).append(port_id)
626 705
             else:
627 706
                 trunk_id = self._get_trunk_id(neutron, pool_key)
628 707
                 try:
@@ -701,8 +780,6 @@ class NestedVIFPool(BaseVIFPool):
701 780
                     net_obj = subnet[subnet_id]
702 781
                     pool_key = self._get_pool_key(host_addr,
703 782
                                                   kuryr_subport['project_id'],
704
-                                                  kuryr_subport[
705
-                                                      'security_groups'],
706 783
                                                   net_obj.id, None)
707 784
 
708 785
                     if action == 'recover':
@@ -711,7 +788,9 @@ class NestedVIFPool(BaseVIFPool):
711 788
 
712 789
                         self._existing_vifs[kuryr_subport['id']] = vif
713 790
                         self._available_ports_pools.setdefault(
714
-                            pool_key, []).append(kuryr_subport['id'])
791
+                            pool_key, {}).setdefault(tuple(sorted(
792
+                                kuryr_subport['security_groups'])),
793
+                                []).append(kuryr_subport['id'])
715 794
 
716 795
                     elif action == 'free':
717 796
                         try:
@@ -721,8 +800,9 @@ class NestedVIFPool(BaseVIFPool):
721 800
                             self._drv_vif._release_vlan_id(
722 801
                                 subport['segmentation_id'])
723 802
                             del self._existing_vifs[kuryr_subport['id']]
724
-                            self._available_ports_pools[pool_key].remove(
725
-                                kuryr_subport['id'])
803
+                            self._available_ports_pools[pool_key][
804
+                                tuple(sorted(kuryr_subport['security_groups']
805
+                                             ))].remove(kuryr_subport['id'])
726 806
                         except n_exc.PortNotFoundClient:
727 807
                             LOG.debug('Unable to release port %s as it no '
728 808
                                       'longer exists.', kuryr_subport['id'])
@@ -752,12 +832,11 @@ class NestedVIFPool(BaseVIFPool):
752 832
             num_ports=num_ports,
753 833
             trunk_ip=trunk_ip)
754 834
 
755
-        pool_key = self._get_pool_key(trunk_ip, project_id, security_groups,
756
-                                      None, subnets)
835
+        pool_key = self._get_pool_key(trunk_ip, project_id, None, subnets)
757 836
         for vif in vifs:
758 837
             self._existing_vifs[vif.id] = vif
759
-            self._available_ports_pools.setdefault(pool_key,
760
-                                                   []).append(vif.id)
838
+            self._available_ports_pools.setdefault(pool_key, {}).setdefault(
839
+                tuple(sorted(security_groups)), []).append(vif.id)
761 840
 
762 841
     def free_pool(self, trunk_ips=None):
763 842
         """Removes subports from the pool and deletes neutron port resource.
@@ -779,19 +858,21 @@ class NestedVIFPool(BaseVIFPool):
779 858
         # on the available_ports_pools dict. The next call forces it to be on
780 859
         # that dict before cleaning it up
781 860
         self._trigger_return_to_pool()
782
-        for pool_key, ports_ids in self._available_ports_pools.items():
861
+        for pool_key, ports in self._available_ports_pools.items():
783 862
             if self._get_pool_key_net(pool_key) != net_id:
784 863
                 continue
785 864
             self._available_ports_pools[pool_key] = []
786 865
             trunk_id = self._get_trunk_id(neutron, pool_key)
866
+            ports_id = [p_id for sg_ports in ports.values()
867
+                        for p_id in sg_ports]
787 868
             try:
788
-                self._drv_vif._remove_subports(neutron, trunk_id, ports_ids)
869
+                self._drv_vif._remove_subports(neutron, trunk_id, ports_id)
789 870
             except n_exc.NeutronClientException:
790 871
                 LOG.exception('Error removing subports from trunk: %s',
791 872
                               trunk_id)
792 873
                 continue
793 874
 
794
-            for port_id in ports_ids:
875
+            for port_id in ports_id:
795 876
                 try:
796 877
                     self._drv_vif._release_vlan_id(
797 878
                         self._existing_vifs[port_id].vlan_id)

+ 298
- 66
kuryr_kubernetes/tests/unit/controller/drivers/test_vif_pool.py View File

@@ -187,15 +187,14 @@ class BaseVIFPool(test_base.TestCase):
187 187
         pod = mock.sentinel.pod
188 188
         project_id = str(uuid.uuid4())
189 189
         subnets = mock.sentinel.subnets
190
-        security_groups = [mock.sentinel.security_groups]
191
-        pool_key = (mock.sentinel.host_addr, project_id,
192
-                    tuple(security_groups))
190
+        security_groups = 'test-sg'
191
+        pool_key = (mock.sentinel.host_addr, project_id)
193 192
         vif = osv_vif.VIFOpenVSwitch(id='0fa0e837-d34e-4580-a6c4-04f5f607d93e')
194 193
         vifs = [vif]
195 194
 
196 195
         m_driver._existing_vifs = {}
197 196
         m_driver._available_ports_pools = {}
198
-        m_driver._last_update = {pool_key: 1}
197
+        m_driver._last_update = {pool_key: {tuple(security_groups): 1}}
199 198
 
200 199
         oslo_cfg.CONF.set_override('ports_pool_min',
201 200
                                    5,
@@ -206,7 +205,8 @@ class BaseVIFPool(test_base.TestCase):
206 205
         m_driver._get_pool_size.return_value = 2
207 206
         vif_driver.request_vifs.return_value = vifs
208 207
 
209
-        cls._populate_pool(m_driver, pool_key, pod, subnets)
208
+        cls._populate_pool(m_driver, pool_key, pod, subnets,
209
+                           tuple(security_groups))
210 210
         m_driver._get_pool_size.assert_called_once()
211 211
         m_driver._drv_vif.request_vifs.assert_called_once()
212 212
 
@@ -218,16 +218,16 @@ class BaseVIFPool(test_base.TestCase):
218 218
         pod = mock.sentinel.pod
219 219
         project_id = str(uuid.uuid4())
220 220
         subnets = mock.sentinel.subnets
221
-        security_groups = [mock.sentinel.security_groups]
222
-        pool_key = (mock.sentinel.host_addr, project_id,
223
-                    tuple(security_groups))
221
+        security_groups = 'test-sg'
222
+        pool_key = (mock.sentinel.host_addr, project_id)
224 223
 
225 224
         oslo_cfg.CONF.set_override('ports_pool_update_frequency',
226 225
                                    15,
227 226
                                    group='vif_pool')
228
-        m_driver._last_update = {pool_key: 1}
227
+        m_driver._last_update = {pool_key: {tuple(security_groups): 1}}
229 228
 
230
-        cls._populate_pool(m_driver, pool_key, pod, subnets)
229
+        cls._populate_pool(m_driver, pool_key, pod, subnets,
230
+                           tuple(security_groups))
231 231
         m_driver._get_pool_size.assert_not_called()
232 232
 
233 233
     @mock.patch('time.time', return_value=50)
@@ -244,9 +244,8 @@ class BaseVIFPool(test_base.TestCase):
244 244
         pod = mock.sentinel.pod
245 245
         project_id = str(uuid.uuid4())
246 246
         subnets = mock.sentinel.subnets
247
-        security_groups = [mock.sentinel.security_groups]
248
-        pool_key = (mock.sentinel.host_addr, project_id,
249
-                    tuple(security_groups))
247
+        security_groups = 'test-sg'
248
+        pool_key = (mock.sentinel.host_addr, project_id)
250 249
 
251 250
         oslo_cfg.CONF.set_override('ports_pool_update_frequency',
252 251
                                    15,
@@ -254,10 +253,11 @@ class BaseVIFPool(test_base.TestCase):
254 253
         oslo_cfg.CONF.set_override('ports_pool_min',
255 254
                                    5,
256 255
                                    group='vif_pool')
257
-        m_driver._last_update = {pool_key: 1}
256
+        m_driver._last_update = {pool_key: {tuple(security_groups): 1}}
258 257
         m_driver._get_pool_size.return_value = 10
259 258
 
260
-        cls._populate_pool(m_driver, pool_key, pod, subnets)
259
+        cls._populate_pool(m_driver, pool_key, pod, subnets,
260
+                           tuple(security_groups))
261 261
         m_driver._get_pool_size.assert_called_once()
262 262
         m_driver._drv_vif.request_vifs.assert_not_called()
263 263
 
@@ -341,11 +341,12 @@ class NeutronVIFPool(test_base.TestCase):
341 341
         port_id = str(uuid.uuid4())
342 342
         port = mock.sentinel.port
343 343
         subnets = mock.sentinel.subnets
344
+        security_groups = 'test-sg'
344 345
 
345 346
         pod = get_pod_obj()
346 347
 
347 348
         m_driver._available_ports_pools = {
348
-            pool_key: collections.deque([port_id])}
349
+            pool_key: {tuple(security_groups): collections.deque([port_id])}}
349 350
         m_driver._existing_vifs = {port_id: port}
350 351
         m_get_port_name.return_value = get_pod_name(pod)
351 352
 
@@ -362,7 +363,7 @@ class NeutronVIFPool(test_base.TestCase):
362 363
         m_driver._get_pool_size.return_value = pool_length
363 364
 
364 365
         self.assertEqual(port, cls._get_port_from_pool(
365
-            m_driver, pool_key, pod, subnets))
366
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
366 367
 
367 368
         neutron.update_port.assert_called_once_with(
368 369
             port_id,
@@ -386,11 +387,12 @@ class NeutronVIFPool(test_base.TestCase):
386 387
         port_id = str(uuid.uuid4())
387 388
         port = mock.sentinel.port
388 389
         subnets = mock.sentinel.subnets
390
+        security_groups = 'test-sg'
389 391
 
390 392
         pod = get_pod_obj()
391 393
 
392 394
         m_driver._available_ports_pools = {
393
-            pool_key: collections.deque([port_id])}
395
+            pool_key: {tuple(security_groups): collections.deque([port_id])}}
394 396
         m_driver._existing_vifs = {port_id: port}
395 397
         m_get_port_name.return_value = get_pod_name(pod)
396 398
 
@@ -404,7 +406,7 @@ class NeutronVIFPool(test_base.TestCase):
404 406
         m_driver._get_pool_size.return_value = pool_length
405 407
 
406 408
         self.assertEqual(port, cls._get_port_from_pool(
407
-            m_driver, pool_key, pod, subnets))
409
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
408 410
 
409 411
         neutron.update_port.assert_called_once_with(
410 412
             port_id,
@@ -424,11 +426,124 @@ class NeutronVIFPool(test_base.TestCase):
424 426
         pod = get_pod_obj()
425 427
         pool_key = mock.sentinel.pool_key
426 428
         subnets = mock.sentinel.subnets
429
+        security_groups = 'test-sg'
430
+
431
+        m_driver._available_ports_pools = {
432
+            pool_key: {tuple(security_groups): collections.deque([])}}
433
+        m_driver._last_update = {pool_key: {tuple(security_groups): 1}}
434
+
435
+        self.assertRaises(exceptions.ResourceNotReady, cls._get_port_from_pool,
436
+                          m_driver, pool_key, pod, subnets,
437
+                          tuple(security_groups))
438
+
439
+        neutron.update_port.assert_not_called()
440
+
441
+    @mock.patch('eventlet.spawn')
442
+    def test__get_port_from_pool_empty_pool_reuse(self, m_eventlet):
443
+        cls = vif_pool.NeutronVIFPool
444
+        m_driver = mock.MagicMock(spec=cls)
445
+        neutron = self.useFixture(k_fix.MockNeutronClient()).client
446
+
447
+        pod = get_pod_obj()
448
+        port_id = str(uuid.uuid4())
449
+        port = mock.sentinel.port
450
+        pool_key = mock.sentinel.pool_key
451
+        subnets = mock.sentinel.subnets
452
+        security_groups = 'test-sg'
453
+        security_groups_2 = 'test-sg2'
454
+
455
+        oslo_cfg.CONF.set_override('port_debug',
456
+                                   False,
457
+                                   group='kubernetes')
458
+        pool_length = 5
459
+        m_driver._get_pool_size.return_value = pool_length
460
+
461
+        m_driver._available_ports_pools = {
462
+            pool_key: {tuple(security_groups): collections.deque([]),
463
+                       tuple(security_groups_2): collections.deque([port_id])}}
464
+        m_driver._last_update = {pool_key: {tuple(security_groups): 1,
465
+                                            tuple(security_groups_2): 0}}
466
+        m_driver._existing_vifs = {port_id: port}
467
+
468
+        self.assertEqual(port, cls._get_port_from_pool(
469
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
470
+
471
+        neutron.update_port.assert_called_once_with(
472
+            port_id,
473
+            {
474
+                "port": {
475
+                    'security_groups': list(security_groups),
476
+                }
477
+            })
478
+        m_eventlet.assert_not_called()
479
+
480
+    @mock.patch('eventlet.spawn')
481
+    def test__get_port_from_pool_empty_pool_reuse_no_update_info(self,
482
+                                                                 m_eventlet):
483
+        cls = vif_pool.NeutronVIFPool
484
+        m_driver = mock.MagicMock(spec=cls)
485
+        neutron = self.useFixture(k_fix.MockNeutronClient()).client
427 486
 
428
-        m_driver._available_ports_pools = {pool_key: collections.deque([])}
487
+        pod = get_pod_obj()
488
+        port_id = str(uuid.uuid4())
489
+        port = mock.sentinel.port
490
+        pool_key = mock.sentinel.pool_key
491
+        subnets = mock.sentinel.subnets
492
+        security_groups = 'test-sg'
493
+        security_groups_2 = 'test-sg2'
494
+
495
+        oslo_cfg.CONF.set_override('port_debug',
496
+                                   False,
497
+                                   group='kubernetes')
498
+        pool_length = 5
499
+        m_driver._get_pool_size.return_value = pool_length
500
+
501
+        m_driver._available_ports_pools = {
502
+            pool_key: {tuple(security_groups): collections.deque([]),
503
+                       tuple(security_groups_2): collections.deque([port_id])}}
504
+        m_driver._last_update = {}
505
+        m_driver._existing_vifs = {port_id: port}
506
+
507
+        self.assertEqual(port, cls._get_port_from_pool(
508
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
509
+
510
+        neutron.update_port.assert_called_once_with(
511
+            port_id,
512
+            {
513
+                "port": {
514
+                    'security_groups': list(security_groups),
515
+                }
516
+            })
517
+        m_eventlet.assert_not_called()
518
+
519
+    def test__get_port_from_pool_empty_pool_reuse_no_ports(self):
520
+        cls = vif_pool.NeutronVIFPool
521
+        m_driver = mock.MagicMock(spec=cls)
522
+        neutron = self.useFixture(k_fix.MockNeutronClient()).client
523
+
524
+        pod = get_pod_obj()
525
+        port_id = str(uuid.uuid4())
526
+        port = mock.sentinel.port
527
+        pool_key = mock.sentinel.pool_key
528
+        subnets = mock.sentinel.subnets
529
+        security_groups = 'test-sg'
530
+        security_groups_2 = 'test-sg2'
531
+
532
+        oslo_cfg.CONF.set_override('port_debug',
533
+                                   False,
534
+                                   group='kubernetes')
535
+        pool_length = 5
536
+        m_driver._get_pool_size.return_value = pool_length
537
+
538
+        m_driver._available_ports_pools = {
539
+            pool_key: {tuple(security_groups): collections.deque([]),
540
+                       tuple(security_groups_2): collections.deque([])}}
541
+        m_driver._last_update = {}
542
+        m_driver._existing_vifs = {port_id: port}
429 543
 
430 544
         self.assertRaises(exceptions.ResourceNotReady, cls._get_port_from_pool,
431
-                          m_driver, pool_key, pod, subnets)
545
+                          m_driver, pool_key, pod, subnets, tuple(
546
+                              security_groups))
432 547
 
433 548
         neutron.update_port.assert_not_called()
434 549
 
@@ -438,7 +553,7 @@ class NeutronVIFPool(test_base.TestCase):
438 553
         m_driver = mock.MagicMock(spec=cls)
439 554
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
440 555
 
441
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
556
+        pool_key = ('node_ip', 'project_id')
442 557
         port_id = str(uuid.uuid4())
443 558
         pool_length = 5
444 559
 
@@ -462,7 +577,6 @@ class NeutronVIFPool(test_base.TestCase):
462 577
                 "port": {
463 578
                     'name': constants.KURYR_PORT_NAME,
464 579
                     'device_id': '',
465
-                    'security_groups': ['security_group']
466 580
                 }
467 581
             })
468 582
         neutron.delete_port.assert_not_called()
@@ -473,7 +587,7 @@ class NeutronVIFPool(test_base.TestCase):
473 587
         m_driver = mock.MagicMock(spec=cls)
474 588
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
475 589
 
476
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
590
+        pool_key = ('node_ip', 'project_id')
477 591
         port_id = str(uuid.uuid4())
478 592
         pool_length = 5
479 593
 
@@ -499,7 +613,7 @@ class NeutronVIFPool(test_base.TestCase):
499 613
         m_driver = mock.MagicMock(spec=cls)
500 614
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
501 615
 
502
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
616
+        pool_key = ('node_ip', 'project_id')
503 617
         port_id = str(uuid.uuid4())
504 618
         pool_length = 10
505 619
         vif = mock.sentinel.vif
@@ -524,7 +638,7 @@ class NeutronVIFPool(test_base.TestCase):
524 638
         m_driver = mock.MagicMock(spec=cls)
525 639
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
526 640
 
527
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
641
+        pool_key = ('node_ip', 'project_id')
528 642
         port_id = str(uuid.uuid4())
529 643
         pool_length = 5
530 644
 
@@ -552,7 +666,6 @@ class NeutronVIFPool(test_base.TestCase):
552 666
                 "port": {
553 667
                     'name': constants.KURYR_PORT_NAME,
554 668
                     'device_id': '',
555
-                    'security_groups': ['security_group']
556 669
                 }
557 670
             })
558 671
         neutron.delete_port.assert_not_called()
@@ -562,7 +675,7 @@ class NeutronVIFPool(test_base.TestCase):
562 675
         m_driver = mock.MagicMock(spec=cls)
563 676
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
564 677
 
565
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
678
+        pool_key = ('node_ip', 'project_id')
566 679
         port_id = str(uuid.uuid4())
567 680
         pool_length = 10
568 681
         vif = mock.sentinel.vif
@@ -588,7 +701,7 @@ class NeutronVIFPool(test_base.TestCase):
588 701
         m_driver = mock.MagicMock(spec=cls)
589 702
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
590 703
 
591
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
704
+        pool_key = ('node_ip', 'project_id')
592 705
         port_id = str(uuid.uuid4())
593 706
         pool_length = 10
594 707
 
@@ -639,8 +752,7 @@ class NeutronVIFPool(test_base.TestCase):
639 752
         vif = mock.sentinel.vif
640 753
         m_to_osvif.return_value = vif
641 754
 
642
-        pool_key = (port['binding:host_id'], port['project_id'],
643
-                    tuple(port['security_groups']), net_id)
755
+        pool_key = (port['binding:host_id'], port['project_id'], net_id)
644 756
         m_driver._get_pool_key.return_value = pool_key
645 757
         m_driver._get_trunks_info.return_value = ({}, {}, {})
646 758
 
@@ -652,7 +764,8 @@ class NeutronVIFPool(test_base.TestCase):
652 764
         m_to_osvif.assert_called_once_with(vif_plugin, port, subnet)
653 765
 
654 766
         self.assertEqual(m_driver._existing_vifs[port_id], vif)
655
-        self.assertEqual(m_driver._available_ports_pools[pool_key], [port_id])
767
+        self.assertEqual(m_driver._available_ports_pools[pool_key],
768
+                         {tuple(port['security_groups']): [port_id]})
656 769
 
657 770
     @mock.patch('kuryr_kubernetes.os_vif_util.neutron_to_osvif_vif')
658 771
     @mock.patch('kuryr_kubernetes.utils.get_subnet')
@@ -681,9 +794,10 @@ class NeutronVIFPool(test_base.TestCase):
681 794
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
682 795
 
683 796
         net_id = mock.sentinel.net_id
684
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
797
+        pool_key = ('node_ip', 'project_id')
685 798
         port_id = str(uuid.uuid4())
686
-        m_driver._available_ports_pools = {pool_key: [port_id]}
799
+        m_driver._available_ports_pools = {pool_key: {
800
+            tuple(['security_group']): [port_id]}}
687 801
         m_driver._existing_vifs = {port_id: mock.sentinel.vif}
688 802
 
689 803
         m_driver._get_pool_key_net.return_value = net_id
@@ -701,9 +815,10 @@ class NeutronVIFPool(test_base.TestCase):
701 815
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
702 816
 
703 817
         net_id = mock.sentinel.net_id
704
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
818
+        pool_key = ('node_ip', 'project_id')
705 819
         port_id = str(uuid.uuid4())
706
-        m_driver._available_ports_pools = {pool_key: [port_id]}
820
+        m_driver._available_ports_pools = {pool_key: {
821
+            tuple(['security_group']): [port_id]}}
707 822
         m_driver._existing_vifs = {}
708 823
         neutron.delete_port.side_effect = n_exc.PortNotFoundClient
709 824
 
@@ -765,11 +880,12 @@ class NestedVIFPool(test_base.TestCase):
765 880
         port_id = str(uuid.uuid4())
766 881
         port = mock.sentinel.port
767 882
         subnets = mock.sentinel.subnets
883
+        security_groups = 'test-sg'
768 884
 
769 885
         pod = get_pod_obj()
770 886
 
771 887
         m_driver._available_ports_pools = {
772
-            pool_key: collections.deque([port_id])}
888
+            pool_key: {tuple(security_groups): collections.deque([port_id])}}
773 889
         m_driver._existing_vifs = {port_id: port}
774 890
         m_get_port_name.return_value = get_pod_name(pod)
775 891
 
@@ -783,7 +899,7 @@ class NestedVIFPool(test_base.TestCase):
783 899
         m_driver._get_pool_size.return_value = pool_length
784 900
 
785 901
         self.assertEqual(port, cls._get_port_from_pool(
786
-            m_driver, pool_key, pod, subnets))
902
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
787 903
 
788 904
         neutron.update_port.assert_called_once_with(
789 905
             port_id,
@@ -806,11 +922,12 @@ class NestedVIFPool(test_base.TestCase):
806 922
         port_id = str(uuid.uuid4())
807 923
         port = mock.sentinel.port
808 924
         subnets = mock.sentinel.subnets
925
+        security_groups = 'test-sg'
809 926
 
810 927
         pod = get_pod_obj()
811 928
 
812 929
         m_driver._available_ports_pools = {
813
-            pool_key: collections.deque([port_id])}
930
+            pool_key: {tuple(security_groups): collections.deque([port_id])}}
814 931
         m_driver._existing_vifs = {port_id: port}
815 932
         m_get_port_name.return_value = get_pod_name(pod)
816 933
 
@@ -824,7 +941,7 @@ class NestedVIFPool(test_base.TestCase):
824 941
         m_driver._get_pool_size.return_value = pool_length
825 942
 
826 943
         self.assertEqual(port, cls._get_port_from_pool(
827
-            m_driver, pool_key, pod, subnets))
944
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
828 945
 
829 946
         neutron.update_port.assert_called_once_with(
830 947
             port_id,
@@ -843,11 +960,124 @@ class NestedVIFPool(test_base.TestCase):
843 960
         pod = mock.sentinel.pod
844 961
         pool_key = mock.sentinel.pool_key
845 962
         subnets = mock.sentinel.subnets
963
+        security_groups = 'test-sg'
846 964
 
847
-        m_driver._available_ports_pools = {pool_key: collections.deque([])}
965
+        m_driver._available_ports_pools = {
966
+            pool_key: {tuple(security_groups): collections.deque([])}}
967
+        m_driver._last_update = {pool_key: {tuple(security_groups): 1}}
848 968
 
849 969
         self.assertRaises(exceptions.ResourceNotReady, cls._get_port_from_pool,
850
-                          m_driver, pool_key, pod, subnets)
970
+                          m_driver, pool_key, pod, subnets, tuple(
971
+                              security_groups))
972
+
973
+        neutron.update_port.assert_not_called()
974
+
975
+    @mock.patch('eventlet.spawn')
976
+    def test__get_port_from_pool_empty_pool_reuse(self, m_eventlet):
977
+        cls = vif_pool.NestedVIFPool
978
+        m_driver = mock.MagicMock(spec=cls)
979
+        neutron = self.useFixture(k_fix.MockNeutronClient()).client
980
+
981
+        pod = mock.sentinel.pod
982
+        port_id = str(uuid.uuid4())
983
+        port = mock.sentinel.port
984
+        pool_key = mock.sentinel.pool_key
985
+        subnets = mock.sentinel.subnets
986
+        security_groups = 'test-sg'
987
+        security_groups_2 = 'test-sg2'
988
+
989
+        oslo_cfg.CONF.set_override('port_debug',
990
+                                   False,
991
+                                   group='kubernetes')
992
+        pool_length = 5
993
+        m_driver._get_pool_size.return_value = pool_length
994
+
995
+        m_driver._available_ports_pools = {
996
+            pool_key: {tuple(security_groups): collections.deque([]),
997
+                       tuple(security_groups_2): collections.deque([port_id])}}
998
+        m_driver._last_update = {pool_key: {tuple(security_groups): 1,
999
+                                            tuple(security_groups_2): 0}}
1000
+        m_driver._existing_vifs = {port_id: port}
1001
+
1002
+        self.assertEqual(port, cls._get_port_from_pool(
1003
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
1004
+
1005
+        neutron.update_port.assert_called_once_with(
1006
+            port_id,
1007
+            {
1008
+                "port": {
1009
+                    'security_groups': list(security_groups),
1010
+                }
1011
+            })
1012
+        m_eventlet.assert_not_called()
1013
+
1014
+    @mock.patch('eventlet.spawn')
1015
+    def test__get_port_from_pool_empty_pool_reuse_no_update_info(self,
1016
+                                                                 m_eventlet):
1017
+        cls = vif_pool.NestedVIFPool
1018
+        m_driver = mock.MagicMock(spec=cls)
1019
+        neutron = self.useFixture(k_fix.MockNeutronClient()).client
1020
+
1021
+        pod = mock.sentinel.pod
1022
+        port_id = str(uuid.uuid4())
1023
+        port = mock.sentinel.port
1024
+        pool_key = mock.sentinel.pool_key
1025
+        subnets = mock.sentinel.subnets
1026
+        security_groups = 'test-sg'
1027
+        security_groups_2 = 'test-sg2'
1028
+
1029
+        oslo_cfg.CONF.set_override('port_debug',
1030
+                                   False,
1031
+                                   group='kubernetes')
1032
+        pool_length = 5
1033
+        m_driver._get_pool_size.return_value = pool_length
1034
+
1035
+        m_driver._available_ports_pools = {
1036
+            pool_key: {tuple(security_groups): collections.deque([]),
1037
+                       tuple(security_groups_2): collections.deque([port_id])}}
1038
+        m_driver._last_update = {}
1039
+        m_driver._existing_vifs = {port_id: port}
1040
+
1041
+        self.assertEqual(port, cls._get_port_from_pool(
1042
+            m_driver, pool_key, pod, subnets, tuple(security_groups)))
1043
+
1044
+        neutron.update_port.assert_called_once_with(
1045
+            port_id,
1046
+            {
1047
+                "port": {
1048
+                    'security_groups': list(security_groups),
1049
+                }
1050
+            })
1051
+        m_eventlet.assert_not_called()
1052
+
1053
+    def test__get_port_from_pool_empty_pool_reuse_no_ports(self):
1054
+        cls = vif_pool.NestedVIFPool
1055
+        m_driver = mock.MagicMock(spec=cls)
1056
+        neutron = self.useFixture(k_fix.MockNeutronClient()).client
1057
+
1058
+        pod = mock.sentinel.pod
1059
+        port_id = str(uuid.uuid4())
1060
+        port = mock.sentinel.port
1061
+        pool_key = mock.sentinel.pool_key
1062
+        subnets = mock.sentinel.subnets
1063
+        security_groups = 'test-sg'
1064
+        security_groups_2 = 'test-sg2'
1065
+
1066
+        oslo_cfg.CONF.set_override('port_debug',
1067
+                                   False,
1068
+                                   group='kubernetes')
1069
+        pool_length = 5
1070
+        m_driver._get_pool_size.return_value = pool_length
1071
+
1072
+        m_driver._available_ports_pools = {
1073
+            pool_key: {tuple(security_groups): collections.deque([]),
1074
+                       tuple(security_groups_2): collections.deque([])}}
1075
+        m_driver._last_update = {}
1076
+        m_driver._existing_vifs = {port_id: port}
1077
+
1078
+        self.assertRaises(exceptions.ResourceNotReady, cls._get_port_from_pool,
1079
+                          m_driver, pool_key, pod, subnets, tuple(
1080
+                              security_groups))
851 1081
 
852 1082
         neutron.update_port.assert_not_called()
853 1083
 
@@ -857,7 +1087,7 @@ class NestedVIFPool(test_base.TestCase):
857 1087
         m_driver = mock.MagicMock(spec=cls)
858 1088
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
859 1089
 
860
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1090
+        pool_key = ('node_ip', 'project_id')
861 1091
         port_id = str(uuid.uuid4())
862 1092
         pool_length = 5
863 1093
 
@@ -880,7 +1110,6 @@ class NestedVIFPool(test_base.TestCase):
880 1110
             {
881 1111
                 "port": {
882 1112
                     'name': constants.KURYR_PORT_NAME,
883
-                    'security_groups': ['security_group']
884 1113
                 }
885 1114
             })
886 1115
         neutron.delete_port.assert_not_called()
@@ -891,7 +1120,7 @@ class NestedVIFPool(test_base.TestCase):
891 1120
         m_driver = mock.MagicMock(spec=cls)
892 1121
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
893 1122
 
894
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1123
+        pool_key = ('node_ip', 'project_id')
895 1124
         port_id = str(uuid.uuid4())
896 1125
         pool_length = 5
897 1126
 
@@ -920,7 +1149,7 @@ class NestedVIFPool(test_base.TestCase):
920 1149
         vif_driver = mock.MagicMock(spec=cls_vif_driver)
921 1150
         m_driver._drv_vif = vif_driver
922 1151
 
923
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1152
+        pool_key = ('node_ip', 'project_id')
924 1153
         port_id = str(uuid.uuid4())
925 1154
         pool_length = 10
926 1155
         vif = mock.MagicMock()
@@ -953,7 +1182,7 @@ class NestedVIFPool(test_base.TestCase):
953 1182
         m_driver = mock.MagicMock(spec=cls)
954 1183
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
955 1184
 
956
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1185
+        pool_key = ('node_ip', 'project_id')
957 1186
         port_id = str(uuid.uuid4())
958 1187
         pool_length = 5
959 1188
 
@@ -977,7 +1206,6 @@ class NestedVIFPool(test_base.TestCase):
977 1206
             {
978 1207
                 "port": {
979 1208
                     'name': constants.KURYR_PORT_NAME,
980
-                    'security_groups': ['security_group']
981 1209
                 }
982 1210
             })
983 1211
         neutron.delete_port.assert_not_called()
@@ -990,7 +1218,7 @@ class NestedVIFPool(test_base.TestCase):
990 1218
         vif_driver = mock.MagicMock(spec=cls_vif_driver)
991 1219
         m_driver._drv_vif = vif_driver
992 1220
 
993
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1221
+        pool_key = ('node_ip', 'project_id')
994 1222
         port_id = str(uuid.uuid4())
995 1223
         pool_length = 10
996 1224
         vif = mock.MagicMock()
@@ -1027,7 +1255,7 @@ class NestedVIFPool(test_base.TestCase):
1027 1255
         vif_driver = mock.MagicMock(spec=cls_vif_driver)
1028 1256
         m_driver._drv_vif = vif_driver
1029 1257
 
1030
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1258
+        pool_key = ('node_ip', 'project_id')
1031 1259
         port_id = str(uuid.uuid4())
1032 1260
         pool_length = 10
1033 1261
         trunk_id = str(uuid.uuid4())
@@ -1163,15 +1391,15 @@ class NestedVIFPool(test_base.TestCase):
1163 1391
         vif = mock.sentinel.vif
1164 1392
         m_to_osvif.return_value = vif
1165 1393
 
1166
-        pool_key = (port['binding:host_id'], port['project_id'],
1167
-                    tuple(port['security_groups']), net_id)
1394
+        pool_key = (port['binding:host_id'], port['project_id'], net_id)
1168 1395
         m_driver._get_pool_key.return_value = pool_key
1169 1396
 
1170 1397
         cls._precreated_ports(m_driver, 'recover')
1171 1398
 
1172 1399
         m_driver._get_trunks_info.assert_called_once()
1173 1400
         self.assertEqual(m_driver._existing_vifs[port_id], vif)
1174
-        self.assertEqual(m_driver._available_ports_pools[pool_key], [port_id])
1401
+        self.assertEqual(m_driver._available_ports_pools[pool_key],
1402
+                         {tuple(port['security_groups']): [port_id]})
1175 1403
         neutron.delete_port.assert_not_called()
1176 1404
 
1177 1405
     def test__precreated_ports_free(self):
@@ -1200,10 +1428,10 @@ class NestedVIFPool(test_base.TestCase):
1200 1428
         m_driver._get_trunks_info.return_value = (p_ports, a_subports,
1201 1429
                                                   subnets)
1202 1430
 
1203
-        pool_key = (port['binding:host_id'], port['project_id'],
1204
-                    tuple(port['security_groups']), net_id)
1431
+        pool_key = (port['binding:host_id'], port['project_id'], net_id)
1205 1432
         m_driver._get_pool_key.return_value = pool_key
1206
-        m_driver._available_ports_pools = {pool_key: [port_id]}
1433
+        m_driver._available_ports_pools = {
1434
+            pool_key: {tuple(port['security_groups']): [port_id]}}
1207 1435
         m_driver._existing_vifs = {port_id: mock.sentinel.vif}
1208 1436
 
1209 1437
         cls._precreated_ports(m_driver, 'free')
@@ -1214,7 +1442,8 @@ class NestedVIFPool(test_base.TestCase):
1214 1442
         m_driver._drv_vif._release_vlan_id.assert_called_once()
1215 1443
 
1216 1444
         self.assertEqual(m_driver._existing_vifs, {})
1217
-        self.assertEqual(m_driver._available_ports_pools[pool_key], [])
1445
+        self.assertEqual(m_driver._available_ports_pools[pool_key][tuple(
1446
+            port['security_groups'])], [])
1218 1447
 
1219 1448
     @mock.patch('kuryr_kubernetes.os_vif_util.'
1220 1449
                 'neutron_to_osvif_vif_nested_vlan')
@@ -1302,8 +1531,7 @@ class NestedVIFPool(test_base.TestCase):
1302 1531
         vif = mock.sentinel.vif
1303 1532
         m_to_osvif.return_value = vif
1304 1533
 
1305
-        pool_key = (port1['binding:host_id'], port1['project_id'],
1306
-                    tuple(port1['security_groups']), net_id)
1534
+        pool_key = (port1['binding:host_id'], port1['project_id'], net_id)
1307 1535
         m_driver._get_pool_key.return_value = pool_key
1308 1536
         cls._precreated_ports(m_driver, 'recover')
1309 1537
 
@@ -1311,7 +1539,8 @@ class NestedVIFPool(test_base.TestCase):
1311 1539
         self.assertEqual(m_driver._existing_vifs, {port_id1: vif,
1312 1540
                                                    port_id2: vif})
1313 1541
         self.assertEqual(m_driver._available_ports_pools[pool_key],
1314
-                         [port_id1, port_id2])
1542
+                         {tuple(port1['security_groups']): [port_id1,
1543
+                                                            port_id2]})
1315 1544
         neutron.delete_port.assert_not_called()
1316 1545
 
1317 1546
     @ddt.data(('recover'), ('free'))
@@ -1382,13 +1611,14 @@ class NestedVIFPool(test_base.TestCase):
1382 1611
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
1383 1612
 
1384 1613
         net_id = mock.sentinel.net_id
1385
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1614
+        pool_key = ('node_ip', 'project_id')
1386 1615
         port_id = str(uuid.uuid4())
1387 1616
         trunk_id = str(uuid.uuid4())
1388 1617
         vif = mock.MagicMock()
1389 1618
         vlan_id = mock.sentinel.vlan_id
1390 1619
         vif.vlan_id = vlan_id
1391
-        m_driver._available_ports_pools = {pool_key: [port_id]}
1620
+        m_driver._available_ports_pools = {pool_key: {
1621
+            tuple(['security_group']): [port_id]}}
1392 1622
         m_driver._existing_vifs = {port_id: vif}
1393 1623
 
1394 1624
         m_driver._get_trunk_id.return_value = trunk_id
@@ -1415,13 +1645,14 @@ class NestedVIFPool(test_base.TestCase):
1415 1645
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
1416 1646
 
1417 1647
         net_id = mock.sentinel.net_id
1418
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1648
+        pool_key = ('node_ip', 'project_id')
1419 1649
         port_id = str(uuid.uuid4())
1420 1650
         trunk_id = str(uuid.uuid4())
1421 1651
         vif = mock.MagicMock()
1422 1652
         vlan_id = mock.sentinel.vlan_id
1423 1653
         vif.vlan_id = vlan_id
1424
-        m_driver._available_ports_pools = {pool_key: [port_id]}
1654
+        m_driver._available_ports_pools = {pool_key: {
1655
+            tuple(['security_group']): [port_id]}}
1425 1656
         m_driver._existing_vifs = {port_id: vif}
1426 1657
 
1427 1658
         m_driver._get_trunk_id.return_value = trunk_id
@@ -1450,13 +1681,14 @@ class NestedVIFPool(test_base.TestCase):
1450 1681
         neutron = self.useFixture(k_fix.MockNeutronClient()).client
1451 1682
 
1452 1683
         net_id = mock.sentinel.net_id
1453
-        pool_key = ('node_ip', 'project_id', tuple(['security_group']))
1684
+        pool_key = ('node_ip', 'project_id')
1454 1685
         port_id = str(uuid.uuid4())
1455 1686
         trunk_id = str(uuid.uuid4())
1456 1687
         vif = mock.MagicMock()
1457 1688
         vlan_id = mock.sentinel.vlan_id
1458 1689
         vif.vlan_id = vlan_id
1459
-        m_driver._available_ports_pools = {pool_key: [port_id]}
1690
+        m_driver._available_ports_pools = {pool_key: {
1691
+            tuple(['security_group']): [port_id]}}
1460 1692
         m_driver._existing_vifs = {}
1461 1693
 
1462 1694
         m_driver._get_trunk_id.return_value = trunk_id

Loading…
Cancel
Save