From 985c3879495ff6e7af8bdc71e48f3d3256b9ba4a Mon Sep 17 00:00:00 2001 From: Yossi Boaron Date: Sun, 11 Mar 2018 15:27:45 +0200 Subject: [PATCH] Services: Add support for K8S service's port edit use case Kubernetes supports edit operation for API resources. This patch extends service handler to support edit operation of K8S service's port field. Change-Id: I286dd8a1383de8eda78637d455e6f8035f178c02 Closes-Bug: 1684096 (cherry picked from commit 677c38b2a6e6c18c251a7b20f2607283c7e831f1) --- kuryr_kubernetes/controller/handlers/lbaas.py | 16 ++++++- .../unit/controller/handlers/test_lbaas.py | 42 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/kuryr_kubernetes/controller/handlers/lbaas.py b/kuryr_kubernetes/controller/handlers/lbaas.py index 720d5c239..7671a3351 100644 --- a/kuryr_kubernetes/controller/handlers/lbaas.py +++ b/kuryr_kubernetes/controller/handlers/lbaas.py @@ -429,11 +429,23 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler): return changed + def _is_pool_in_spec(self, pool, lbaas_state, lbaas_spec): + # NOTE(yboaron): in order to check if a specific pool is in lbaas_spec + # we should: + # 1. get the listener that pool is attached to + # 2. check if listener's attributes appear in lbaas_spec. + for l in lbaas_state.listeners: + if l.id != pool.listener_id: + continue + for port in lbaas_spec.ports: + if l.port == port.port and l.protocol == port.protocol: + return True + return False + def _remove_unused_pools(self, endpoints, lbaas_state, lbaas_spec): - current_pools = {m.pool_id for m in lbaas_state.members} removed_ids = set() for pool in lbaas_state.pools: - if pool.id in current_pools: + if self._is_pool_in_spec(pool, lbaas_state, lbaas_spec): continue self._drv_lbaas.release_pool(endpoints, lbaas_state.loadbalancer, diff --git a/kuryr_kubernetes/tests/unit/controller/handlers/test_lbaas.py b/kuryr_kubernetes/tests/unit/controller/handlers/test_lbaas.py index 3a9106dfb..084a58782 100644 --- a/kuryr_kubernetes/tests/unit/controller/handlers/test_lbaas.py +++ b/kuryr_kubernetes/tests/unit/controller/handlers/test_lbaas.py @@ -712,6 +712,48 @@ class TestLoadBalancerHandler(test_base.TestCase): self.assertEqual([], observed_targets) self.assertEqual(expected_ip, str(state.loadbalancer.ip)) + @mock.patch('kuryr_kubernetes.controller.drivers.base' + '.PodSubnetsDriver.get_instance') + @mock.patch('kuryr_kubernetes.controller.drivers.base' + '.PodProjectDriver.get_instance') + @mock.patch('kuryr_kubernetes.controller.drivers.base' + '.LBaaSDriver.get_instance') + def test_sync_lbaas_members_svc_listener_port_edit( + self, m_get_drv_lbaas, m_get_drv_project, m_get_drv_subnets): + # REVISIT(ivc): test methods separately and verify ensure/release + project_id = uuidutils.generate_uuid() + subnet_id = uuidutils.generate_uuid() + current_ip = '1.1.1.1' + current_targets = { + '1.1.1.101': (1001, 10001)} + expected_ip = '1.1.1.1' + expected_targets = { + '1.1.1.101': (1201, 10001)} + endpoints = self._generate_endpoints(expected_targets) + state = self._generate_lbaas_state( + current_ip, current_targets, project_id, subnet_id) + spec = self._generate_lbaas_spec(expected_ip, expected_targets, + project_id, subnet_id) + + m_drv_lbaas = mock.Mock(wraps=FakeLBaaSDriver()) + m_drv_project = mock.Mock() + m_drv_project.get_project.return_value = project_id + m_drv_subnets = mock.Mock() + m_drv_subnets.get_subnets.return_value = { + subnet_id: mock.sentinel.subnet} + m_get_drv_lbaas.return_value = m_drv_lbaas + m_get_drv_project.return_value = m_drv_project + m_get_drv_subnets.return_value = m_drv_subnets + + handler = h_lbaas.LoadBalancerHandler() + + with mock.patch.object(handler, '_get_pod_subnet') as m_get_pod_subnet: + m_get_pod_subnet.return_value = subnet_id + handler._sync_lbaas_members(endpoints, state, spec) + + self.assertEqual(expected_ip, str(state.loadbalancer.ip)) + m_drv_lbaas.release_pool.assert_called_once() + def test_get_lbaas_spec(self): self.skipTest("skipping until generalised annotation handling is " "implemented")