Browse Source

Fix SG rules on targetPort update

After applying a Network Policy and updating an existent Service so that
all 'targetPorts' are allowed by the policy, the SG rules are not being
created with the required 'remote_ip_prefix'. Also, when the service is
again updated with a 'targetPort' that is not allowed by the policy the
respective SG rule is not deleted.
This commit fixes the issue by associating 'targetPort' field to the 
'LBaaSPortSpec' versioned object, which allows Kuryr to accounts for
changes in not only 'name', 'port' and 'protocol' Kubernetes services'
fields, but also 'targetPorts'. In addition, the LBaaS SG from the
LBaaS state annotation is updated to match the SG stated in the
LBaaS spec annotation, which has the updated SG to be applied.

Closes-Bug: #1814920
Change-Id: Ifcdd1889a813c1eb078064facfb2ede83a179887
Maysa Macedo 2 months ago
parent
commit
9c2fcbc3e3

+ 27
- 5
kuryr_kubernetes/controller/handlers/lbaas.py View File

@@ -122,7 +122,8 @@ class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
122 122
     def _get_service_ports(self, service):
123 123
         return [{'name': port.get('name'),
124 124
                  'protocol': port.get('protocol', 'TCP'),
125
-                 'port': port['port']}
125
+                 'port': port['port'],
126
+                 'targetPort': port['targetPort']}
126 127
                 for port in service['spec']['ports']]
127 128
 
128 129
     def _has_port_changes(self, service, lbaas_spec):
@@ -131,7 +132,10 @@ class LBaaSSpecHandler(k8s_base.ResourceEventHandler):
131 132
         fields = obj_lbaas.LBaaSPortSpec.fields
132 133
         svc_port_set = {tuple(port[attr] for attr in fields)
133 134
                         for port in self._get_service_ports(service)}
134
-        spec_port_set = {tuple(getattr(port, attr) for attr in fields)
135
+
136
+        spec_port_set = {tuple(getattr(port, attr)
137
+                         for attr in fields
138
+                         if port.obj_attr_is_set(attr))
135 139
                          for port in lbaas_spec.ports}
136 140
 
137 141
         if svc_port_set != spec_port_set:
@@ -311,11 +315,17 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
311 315
                    self._is_lbaas_spec_in_sync(endpoints, lbaas_spec))
312 316
 
313 317
     def _is_lbaas_spec_in_sync(self, endpoints, lbaas_spec):
314
-        # REVISIT(ivc): consider other options instead of using 'name'
315
-        ep_ports = list(set(port.get('name')
318
+        ports = lbaas_spec.ports
319
+        ep_ports = list(set((port.get('name'), port.get('port'))
320
+                            if ports[0].obj_attr_is_set('targetPort')
321
+                            else port.get('name')
316 322
                             for subset in endpoints.get('subsets', [])
317 323
                             for port in subset.get('ports', [])))
318
-        spec_ports = [port.name for port in lbaas_spec.ports]
324
+
325
+        spec_ports = [(port.name, port.targetPort)
326
+                      if port.obj_attr_is_set('targetPort')
327
+                      else port.name
328
+                      for port in ports]
319 329
 
320 330
         return sorted(ep_ports) == sorted(spec_ports)
321 331
 
@@ -352,6 +362,7 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
352 362
         pool_by_lsnr_port = {(lsnr_by_id[p.listener_id].protocol,
353 363
                               lsnr_by_id[p.listener_id].port): p
354 364
                              for p in lbaas_state.pools}
365
+
355 366
         # NOTE(yboaron): Since LBaaSv2 doesn't support UDP load balancing,
356 367
         #              the LBaaS driver will return 'None' in case of UDP port
357 368
         #              listener creation.
@@ -387,6 +398,7 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
387 398
                     except KeyError:
388 399
                         LOG.debug("No pool found for port: %r", port_name)
389 400
                         continue
401
+
390 402
                     if (target_ip, target_port, pool.id) in current_targets:
391 403
                         continue
392 404
                     # TODO(apuimedo): Do not pass subnet_id at all when in
@@ -410,6 +422,7 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
410 422
                         listener_port = lsnr_by_id[pool.listener_id].port
411 423
                     else:
412 424
                         listener_port = None
425
+
413 426
                     member = self._drv_lbaas.ensure_member(
414 427
                         loadbalancer=lbaas_state.loadbalancer,
415 428
                         pool=pool,
@@ -636,6 +649,15 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
636 649
                 lbaas_state.service_pub_ip_info = None
637 650
                 changed = True
638 651
 
652
+        default_sgs = config.CONF.neutron_defaults.pod_security_groups
653
+        lbaas_spec_sgs = lbaas_spec.security_groups_ids
654
+        if lb.security_groups and lb.security_groups != lbaas_spec_sgs:
655
+            sgs = [lb_sg for lb_sg in lb.security_groups
656
+                   if lb_sg not in default_sgs]
657
+            if lbaas_spec_sgs != default_sgs:
658
+                sgs.extend(lbaas_spec_sgs)
659
+            lb.security_groups = sgs
660
+
639 661
         lbaas_state.loadbalancer = lb
640 662
         return changed
641 663
 

+ 4
- 1
kuryr_kubernetes/objects/lbaas.py View File

@@ -120,12 +120,15 @@ class LBaaSState(k_obj.KuryrK8sObjectBase):
120 120
 
121 121
 @obj_base.VersionedObjectRegistry.register
122 122
 class LBaaSPortSpec(k_obj.KuryrK8sObjectBase):
123
-    VERSION = '1.0'
123
+    VERSION = '1.1'
124
+    # Version 1.0: Initial version
125
+    # Version 1.1: Added targetPort field.
124 126
 
125 127
     fields = {
126 128
         'name': obj_fields.StringField(nullable=True),
127 129
         'protocol': obj_fields.StringField(),
128 130
         'port': obj_fields.IntegerField(),
131
+        'targetPort': obj_fields.IntegerField(),
129 132
     }
130 133
 
131 134
 

+ 23
- 16
kuryr_kubernetes/tests/unit/controller/handlers/test_lbaas.py View File

@@ -201,12 +201,12 @@ class TestLBaaSSpecHandler(test_base.TestCase):
201 201
     def test_get_service_ports(self):
202 202
         m_handler = mock.Mock(spec=h_lbaas.LBaaSSpecHandler)
203 203
         service = {'spec': {'ports': [
204
-            {'port': 1},
205
-            {'port': 2, 'name': 'X', 'protocol': 'UDP'}
204
+            {'port': 1, 'targetPort': 1},
205
+            {'port': 2, 'name': 'X', 'protocol': 'UDP', 'targetPort': 2}
206 206
         ]}}
207 207
         expected_ret = [
208
-            {'port': 1, 'name': None, 'protocol': 'TCP'},
209
-            {'port': 2, 'name': 'X', 'protocol': 'UDP'}]
208
+            {'port': 1, 'name': None, 'protocol': 'TCP', 'targetPort': 1},
209
+            {'port': 2, 'name': 'X', 'protocol': 'UDP', 'targetPort': 2}]
210 210
 
211 211
         ret = h_lbaas.LBaaSSpecHandler._get_service_ports(m_handler, service)
212 212
         self.assertEqual(expected_ret, ret)
@@ -215,13 +215,15 @@ class TestLBaaSSpecHandler(test_base.TestCase):
215 215
         m_handler = mock.Mock(spec=h_lbaas.LBaaSSpecHandler)
216 216
         m_service = mock.MagicMock()
217 217
         m_handler._get_service_ports.return_value = [
218
-            {'port': 1, 'name': 'X', 'protocol': 'TCP'},
218
+            {'port': 1, 'name': 'X', 'protocol': 'TCP', 'targetPort': 1},
219 219
         ]
220 220
 
221 221
         m_lbaas_spec = mock.MagicMock()
222 222
         m_lbaas_spec.ports = [
223
-            obj_lbaas.LBaaSPortSpec(name='X', protocol='TCP', port=1),
224
-            obj_lbaas.LBaaSPortSpec(name='Y', protocol='TCP', port=2),
223
+            obj_lbaas.LBaaSPortSpec(name='X', protocol='TCP', port=1,
224
+                                    targetPort=1),
225
+            obj_lbaas.LBaaSPortSpec(name='Y', protocol='TCP', port=2,
226
+                                    targetPort=2),
225 227
         ]
226 228
 
227 229
         ret = h_lbaas.LBaaSSpecHandler._has_port_changes(
@@ -233,14 +235,16 @@ class TestLBaaSSpecHandler(test_base.TestCase):
233 235
         m_handler = mock.Mock(spec=h_lbaas.LBaaSSpecHandler)
234 236
         m_service = mock.MagicMock()
235 237
         m_handler._get_service_ports.return_value = [
236
-            {'port': 1, 'name': 'X', 'protocol': 'TCP'},
237
-            {'port': 2, 'name': 'Y', 'protocol': 'TCP'}
238
+            {'port': 1, 'name': 'X', 'protocol': 'TCP', 'targetPort': 1},
239
+            {'port': 2, 'name': 'Y', 'protocol': 'TCP', 'targetPort': 2}
238 240
         ]
239 241
 
240 242
         m_lbaas_spec = mock.MagicMock()
241 243
         m_lbaas_spec.ports = [
242
-            obj_lbaas.LBaaSPortSpec(name='X', protocol='TCP', port=1),
243
-            obj_lbaas.LBaaSPortSpec(name='Y', protocol='TCP', port=2),
244
+            obj_lbaas.LBaaSPortSpec(name='X', protocol='TCP', port=1,
245
+                                    targetPort=1),
246
+            obj_lbaas.LBaaSPortSpec(name='Y', protocol='TCP', port=2,
247
+                                    targetPort=2),
244 248
         ]
245 249
 
246 250
         ret = h_lbaas.LBaaSSpecHandler._has_port_changes(
@@ -673,9 +677,11 @@ class TestLoadBalancerHandler(test_base.TestCase):
673 677
 
674 678
     def test_is_lbaas_spec_in_sync(self):
675 679
         names = ['a', 'b', 'c']
676
-        endpoints = {'subsets': [{'ports': [{'name': n} for n in names]}]}
680
+        endpoints = {'subsets': [{'ports': [{'name': n, 'port': 1}
681
+                     for n in names]}]}
677 682
         lbaas_spec = obj_lbaas.LBaaSServiceSpec(ports=[
678
-            obj_lbaas.LBaaSPortSpec(name=n) for n in reversed(names)])
683
+            obj_lbaas.LBaaSPortSpec(name=n, targetPort=1)
684
+            for n in reversed(names)])
679 685
 
680 686
         m_handler = mock.Mock(spec=h_lbaas.LoadBalancerHandler)
681 687
         ret = h_lbaas.LoadBalancerHandler._is_lbaas_spec_in_sync(
@@ -748,10 +754,11 @@ class TestLoadBalancerHandler(test_base.TestCase):
748 754
             ip=vip,
749 755
             project_id=project_id,
750 756
             subnet_id=subnet_id,
751
-            ports=[obj_lbaas.LBaaSPortSpec(name=str(port),
757
+            ports=[obj_lbaas.LBaaSPortSpec(name=str(t[0]),
752 758
                                            protocol=prot,
753
-                                           port=port)
754
-                   for port in set(t[0] for t in targets.values())],
759
+                                           port=t[0],
760
+                                           targetPort=t[1])
761
+                   for t in targets.values()],
755 762
             type=lbaas_type)
756 763
 
757 764
     def _generate_endpoints(self, targets):

+ 1
- 1
kuryr_kubernetes/tests/unit/test_object.py View File

@@ -28,7 +28,7 @@ object_data = {
28 28
     'LBaaSLoadBalancer': '1.3-8bc0a9bdbd160da67572aa38784378d1',
29 29
     'LBaaSMember': '1.0-a770c6884c27d6d8c21186b27d0e2ccb',
30 30
     'LBaaSPool': '1.1-6e77370d7632a902445444249eb77b01',
31
-    'LBaaSPortSpec': '1.0-51dfa3436bec32db3614720056fcc83f',
31
+    'LBaaSPortSpec': '1.1-fcfa2fd07f4bc5619b96fa41bcdf6e23',
32 32
     'LBaaSPubIp': '1.0-83992edec2c60fb4ab8998ea42a4ff74',
33 33
     'LBaaSRouteNotifEntry': '1.0-dd2f2be956f68814b1f47cb13483a885',
34 34
     'LBaaSRouteNotifier': '1.0-f0bfd8e772434abe7557930d7e0180c1',

Loading…
Cancel
Save