Ensure kuryrnet does not perform multiple repopulations

This patch makes use of the KuryrNet CRD spec to ensure pools
population actions on a new namespace only happen once.

Closes-Bug: 1833032

Change-Id: Ia561833d594c55c17a9dc1a588d39bf3410cdf81
This commit is contained in:
Luis Tomas Bolivar 2019-06-14 14:07:26 +02:00
parent 0d931a0329
commit e2e63cfc4d
7 changed files with 69 additions and 23 deletions

View File

@ -114,8 +114,9 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
e_rule["security_group_rule"]["id"] = sgr_id
# Annotate kuryrnetpolicy CRD with current policy and ruleset
pod_selector = policy['spec'].get('podSelector')
driver_utils.patch_kuryr_crd(crd, i_rules, e_rules, pod_selector,
np_spec=policy['spec'])
driver_utils.patch_kuryrnetworkpolicy_crd(crd, i_rules, e_rules,
pod_selector,
np_spec=policy['spec'])
if existing_pod_selector != pod_selector:
return existing_pod_selector

View File

@ -442,8 +442,9 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
e_matched, e_rules = _parse_rules('egress', crd, pod=pod)
if i_matched or e_matched:
driver_utils.patch_kuryr_crd(crd, i_rules,
e_rules, crd_selector)
driver_utils.patch_kuryrnetworkpolicy_crd(crd, i_rules,
e_rules,
crd_selector)
crd_pod_selectors.append(crd_selector)
return crd_pod_selectors
@ -463,8 +464,9 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
egress_rule_list, "egress", pod_ip)
if i_matched or e_matched:
driver_utils.patch_kuryr_crd(crd, i_rules, e_rules,
crd_selector)
driver_utils.patch_kuryrnetworkpolicy_crd(crd, i_rules,
e_rules,
crd_selector)
crd_pod_selectors.append(crd_selector)
return crd_pod_selectors
@ -492,7 +494,7 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
egress_rule_list, "egress", ns_name)
if i_matched or e_matched:
driver_utils.patch_kuryr_crd(
driver_utils.patch_kuryrnetworkpolicy_crd(
crd, i_rules, e_rules, crd_selector)
def create_namespace_sg_rules(self, namespace):
@ -511,8 +513,9 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
'egress', crd, namespace=namespace)
if i_matched or e_matched:
driver_utils.patch_kuryr_crd(crd, i_rules,
e_rules, crd_selector)
driver_utils.patch_kuryrnetworkpolicy_crd(crd, i_rules,
e_rules,
crd_selector)
def update_namespace_sg_rules(self, namespace):
LOG.debug("Updating sg rule for namespace: %s",

View File

@ -218,7 +218,20 @@ def delete_security_group_rule(security_group_rule_id):
raise
def patch_kuryr_crd(crd, i_rules, e_rules, pod_selector, np_spec=None):
def patch_kuryrnet_crd(crd, populated=True):
kubernetes = clients.get_kubernetes_client()
crd_name = crd['metadata']['name']
LOG.debug('Patching KuryrNet CRD %s' % crd_name)
try:
kubernetes.patch_crd('spec', crd['metadata']['selfLink'],
{'populated': populated})
except k_exc.K8sClientException:
LOG.exception('Error updating kuryrnet CRD %s', crd_name)
raise
def patch_kuryrnetworkpolicy_crd(crd, i_rules, e_rules, pod_selector,
np_spec=None):
kubernetes = clients.get_kubernetes_client()
crd_name = crd['metadata']['name']
if not np_spec:

View File

@ -16,6 +16,8 @@ from oslo_log import log as logging
from kuryr_kubernetes import constants
from kuryr_kubernetes.controller.drivers import base as drivers
from kuryr_kubernetes.controller.drivers import utils as driver_utils
from kuryr_kubernetes import exceptions
from kuryr_kubernetes.handlers import k8s_base
from kuryr_kubernetes import utils
@ -42,18 +44,37 @@ class KuryrNetHandler(k8s_base.ResourceEventHandler):
def on_added(self, kuryrnet_crd):
namespace = kuryrnet_crd['metadata']['annotations'].get(
'namespaceName')
subnet_id = kuryrnet_crd['spec'].get('subnetId')
if kuryrnet_crd['spec'].get('populated'):
LOG.debug("Subnet %s already populated", subnet_id)
return
# NOTE(ltomasbo): using namespace name instead of object as it is not
# required
project_id = self._drv_project.get_project(namespace)
subnet_id = kuryrnet_crd['spec'].get('subnetId')
subnets = self._drv_subnets.get_namespace_subnet(namespace, subnet_id)
sg_id = kuryrnet_crd['spec'].get('sgId', [])
nodes = utils.get_nodes_ips()
# NOTE(ltomasbo): Patching the kuryrnet_crd here instead of after
# populate_pool method to ensure initial repopulation is not happening
# twice upon unexpected problems, such as neutron failing to
# transition the ports to ACTIVE or being too slow replying.
# In such case, even though the repopulation actions got triggered,
# the pools will not get the ports loaded (as they are not ACTIVE)
# and new population actions may be triggered if the controller was
# restarted before performing the populated=true patching.
driver_utils.patch_kuryrnet_crd(kuryrnet_crd, populated=True)
# TODO(ltomasbo): Skip the master node where pods are not usually
# allocated.
for node_ip in nodes:
LOG.debug("Populating subnet pool %s at node %s", subnet_id,
node_ip)
self._drv_vif_pool.populate_pool(node_ip, project_id, subnets,
sg_id)
try:
self._drv_vif_pool.populate_pool(node_ip, project_id, subnets,
sg_id)
except exceptions.ResourceNotReady:
# Ensure the repopulation is retriggered if the system was not
# yet ready to perform the repopulation actions
driver_utils.patch_kuryrnet_crd(kuryrnet_crd, populated=False)
raise

View File

@ -177,6 +177,11 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
kubernetes = clients.get_kubernetes_client()
net_crd_name = "ns-" + namespace
spec = {k: v for k, v in net_crd_spec.items()}
# NOTE(ltomasbo): To know if the subnet has bee populated with pools.
# This is only needed by the kuryrnet handler to skip actions. But its
# addition does not have any impact if not used
spec['populated'] = False
net_crd = {
'apiVersion': 'openstack.org/v1',
'kind': 'KuryrNet',

View File

@ -408,14 +408,14 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
self.assertEqual(matched, False)
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'patch_kuryr_crd')
'patch_kuryrnetworkpolicy_crd')
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'get_kuryrnetpolicy_crds')
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'delete_security_group_rule')
@mock.patch('kuryr_kubernetes.controller.drivers.utils.get_pod_ip')
def test_delete_sg_rules(self, m_get_pod_ip, m_delete_sg_rule,
m_get_knp_crds, m_patch_kuryr_crd):
m_get_knp_crds, m_patch_kuryrnetworkpolicy_crd):
crd = self._crd_with_rule
i_rule = crd['spec'].get('ingressSgRules')[0]
sgr_id = i_rule['security_group_rule'].get('id')
@ -435,7 +435,7 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
m_get_knp_crds.assert_called_once()
m_get_pod_ip.assert_called_once_with(pod)
m_delete_sg_rule.assert_called_once_with(sgr_id)
m_patch_kuryr_crd.assert_called_with(
m_patch_kuryrnetworkpolicy_crd.assert_called_with(
crd, i_rules, e_rules, crd['spec'].get('podSelector'))
@mock.patch('kuryr_kubernetes.config.CONF')
@ -529,13 +529,13 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
self.assertEqual([str(self._sg_id), str(self._sg_id2)], resp)
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'patch_kuryr_crd')
'patch_kuryrnetworkpolicy_crd')
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'delete_security_group_rule')
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'get_kuryrnetpolicy_crds')
def test_delete_namespace_sg_rule(self, m_get_knp_crd, m_delete_sg_rule,
m_patch_kuryr_crd):
m_patch_kuryrnetworkpolicy_crd):
cls = network_policy_security_groups.NetworkPolicySecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
i_rule = get_matched_crd_obj()['spec']['ingressSgRules'][0]
@ -547,17 +547,17 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
m_get_knp_crd.assert_called_once()
m_delete_sg_rule.assert_called_once_with(sg_rule_id)
m_patch_kuryr_crd.assert_called_once()
m_patch_kuryrnetworkpolicy_crd.assert_called_once()
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'patch_kuryr_crd')
'patch_kuryrnetworkpolicy_crd')
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'delete_security_group_rule')
@mock.patch('kuryr_kubernetes.controller.drivers.utils.'
'get_kuryrnetpolicy_crds')
def test_delete_namespace_sg_rule_no_match(self, m_get_knp_crd,
m_delete_sg_rule,
m_patch_kuryr_crd):
m_patch_kuryrnetworkpolicy_crd):
cls = network_policy_security_groups.NetworkPolicySecurityGroupsDriver
m_driver = mock.MagicMock(spec=cls)
@ -568,7 +568,7 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
m_get_knp_crd.assert_called_once()
m_delete_sg_rule.assert_not_called()
m_patch_kuryr_crd.assert_not_called()
m_patch_kuryrnetworkpolicy_crd.assert_not_called()
@mock.patch('kuryr_kubernetes.controller.drivers.'
'network_policy_security_groups._create_sg_rule')

View File

@ -16,6 +16,7 @@ import mock
from kuryr_kubernetes.controller.drivers import base as drivers
from kuryr_kubernetes.controller.drivers import namespace_subnet as subnet_drv
from kuryr_kubernetes.controller.drivers import utils as driver_utils
from kuryr_kubernetes.controller.drivers import vif_pool
from kuryr_kubernetes.controller.handlers import kuryrnet
from kuryr_kubernetes.tests import base as test_base
@ -76,8 +77,9 @@ class TestKuryrNetHandler(test_base.TestCase):
self.assertEqual(subnet_driver, handler._drv_subnets)
self.assertEqual(vif_pool_driver, handler._drv_vif_pool)
@mock.patch.object(driver_utils, 'patch_kuryrnet_crd')
@mock.patch.object(utils, 'get_nodes_ips')
def test_on_added(self, m_get_nodes_ips):
def test_on_added(self, m_get_nodes_ips, m_patch_kn_crd):
m_get_nodes_ips.return_value = ['node-ip']
kuryrnet.KuryrNetHandler.on_added(self._handler, self._kuryrnet_crd)
@ -90,3 +92,4 @@ class TestKuryrNetHandler(test_base.TestCase):
self._project_id,
self._subnets,
[])
m_patch_kn_crd.assert_called_once()