Ensure lb sg rules are updated upon namespace label updates

This patch ensures lb sg rules are updated when NPs reference to
namespace labels through namespace selectors. The affected svc
will be updated after namespace label is updated and due to that it
either starts or stops being referenced by the NP.

Closes-Bug: 1845977
Change-Id: I2d454f387676201066decce9f99d2f59b1ff6a66
This commit is contained in:
Luis Tomas Bolivar 2019-09-30 18:16:37 +02:00
parent de68d1e9d8
commit 232509ee66
3 changed files with 52 additions and 10 deletions

View File

@ -509,6 +509,7 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
LOG.debug("Deleting sg rule for namespace: %s", LOG.debug("Deleting sg rule for namespace: %s",
ns_name) ns_name)
crd_selectors = []
knp_crds = driver_utils.get_kuryrnetpolicy_crds() knp_crds = driver_utils.get_kuryrnetpolicy_crds()
for crd in knp_crds.get('items'): for crd in knp_crds.get('items'):
crd_selector = crd['spec'].get('podSelector') crd_selector = crd['spec'].get('podSelector')
@ -523,11 +524,14 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
if i_matched or e_matched: if i_matched or e_matched:
driver_utils.patch_kuryrnetworkpolicy_crd( driver_utils.patch_kuryrnetworkpolicy_crd(
crd, i_rules, e_rules, crd_selector) crd, i_rules, e_rules, crd_selector)
crd_selectors.append(crd_selector)
return crd_selectors
def create_namespace_sg_rules(self, namespace): def create_namespace_sg_rules(self, namespace):
kubernetes = clients.get_kubernetes_client() kubernetes = clients.get_kubernetes_client()
ns_name = namespace['metadata']['name'] ns_name = namespace['metadata']['name']
LOG.debug("Creating sg rule for namespace: %s", ns_name) LOG.debug("Creating sg rule for namespace: %s", ns_name)
crd_selectors = []
namespace = kubernetes.get( namespace = kubernetes.get(
'{}/namespaces/{}'.format(constants.K8S_API_BASE, ns_name)) '{}/namespaces/{}'.format(constants.K8S_API_BASE, ns_name))
knp_crds = driver_utils.get_kuryrnetpolicy_crds() knp_crds = driver_utils.get_kuryrnetpolicy_crds()
@ -543,12 +547,16 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
driver_utils.patch_kuryrnetworkpolicy_crd(crd, i_rules, driver_utils.patch_kuryrnetworkpolicy_crd(crd, i_rules,
e_rules, e_rules,
crd_selector) crd_selector)
crd_selectors.append(crd_selector)
return crd_selectors
def update_namespace_sg_rules(self, namespace): def update_namespace_sg_rules(self, namespace):
LOG.debug("Updating sg rule for namespace: %s", LOG.debug("Updating sg rule for namespace: %s",
namespace['metadata']['name']) namespace['metadata']['name'])
self.delete_namespace_sg_rules(namespace) crd_selectors = []
self.create_namespace_sg_rules(namespace) crd_selectors.extend(self.delete_namespace_sg_rules(namespace))
crd_selectors.extend(self.create_namespace_sg_rules(namespace))
return crd_selectors
def create_namespace_sg(self, namespace, project_id, crd_spec): def create_namespace_sg(self, namespace, project_id, crd_spec):
LOG.debug("Security group driver does not create SGs for the " LOG.debug("Security group driver does not create SGs for the "

View File

@ -20,7 +20,7 @@ from oslo_serialization import jsonutils
from kuryr_kubernetes import clients from kuryr_kubernetes import clients
from kuryr_kubernetes import constants from kuryr_kubernetes import constants
from kuryr_kubernetes.controller.drivers import base as drivers from kuryr_kubernetes.controller.drivers import base as drivers
from kuryr_kubernetes.controller.drivers import utils as drivers_utils from kuryr_kubernetes.controller.drivers import utils as driver_utils
from kuryr_kubernetes import exceptions from kuryr_kubernetes import exceptions
from kuryr_kubernetes.handlers import k8s_base from kuryr_kubernetes.handlers import k8s_base
from kuryr_kubernetes import utils from kuryr_kubernetes import utils
@ -57,20 +57,28 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
self._drv_vif_pool = drivers.VIFPoolDriver.get_instance( self._drv_vif_pool = drivers.VIFPoolDriver.get_instance(
specific_driver='multi_pool') specific_driver='multi_pool')
self._drv_vif_pool.set_vif_driver() self._drv_vif_pool.set_vif_driver()
if self._is_network_policy_enabled():
self._drv_lbaas = drivers.LBaaSDriver.get_instance()
self._drv_svc_sg = (
drivers.ServiceSecurityGroupsDriver.get_instance())
def on_present(self, namespace): def on_present(self, namespace):
ns_name = namespace['metadata']['name'] ns_name = namespace['metadata']['name']
current_namespace_labels = namespace['metadata'].get('labels') current_namespace_labels = namespace['metadata'].get('labels')
previous_namespace_labels = drivers_utils.get_annotated_labels( previous_namespace_labels = driver_utils.get_annotated_labels(
namespace, constants.K8S_ANNOTATION_NAMESPACE_LABEL) namespace, constants.K8S_ANNOTATION_NAMESPACE_LABEL)
LOG.debug("Got previous namespace labels from annotation: %r", LOG.debug("Got previous namespace labels from annotation: %r",
previous_namespace_labels) previous_namespace_labels)
if current_namespace_labels != previous_namespace_labels:
self._drv_sg.update_namespace_sg_rules(namespace)
self._set_namespace_labels(namespace, current_namespace_labels)
project_id = self._drv_project.get_project(namespace) project_id = self._drv_project.get_project(namespace)
if current_namespace_labels != previous_namespace_labels:
crd_selectors = self._drv_sg.update_namespace_sg_rules(namespace)
self._set_namespace_labels(namespace, current_namespace_labels)
if (self._is_network_policy_enabled() and crd_selectors and
oslo_cfg.CONF.octavia_defaults.enforce_sg_rules):
services = driver_utils.get_services()
self._update_services(services, crd_selectors, project_id)
net_crd_id = self._get_net_crd_id(namespace) net_crd_id = self._get_net_crd_id(namespace)
if net_crd_id: if net_crd_id:
LOG.debug("CRD existing at the new namespace") LOG.debug("CRD existing at the new namespace")
@ -149,7 +157,13 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
LOG.debug("There is no security group associated with the " LOG.debug("There is no security group associated with the "
"namespace to be deleted") "namespace to be deleted")
self._del_kuryrnet_crd(net_crd_name) self._del_kuryrnet_crd(net_crd_name)
self._drv_sg.delete_namespace_sg_rules(namespace) crd_selectors = self._drv_sg.delete_namespace_sg_rules(namespace)
if (self._is_network_policy_enabled() and crd_selectors and
oslo_cfg.CONF.octavia_defaults.enforce_sg_rules):
project_id = self._drv_project.get_project(namespace)
services = driver_utils.get_services()
self._update_services(services, crd_selectors, project_id)
def is_ready(self, quota): def is_ready(self, quota):
if not utils.has_kuryr_crd(constants.K8S_API_CRD_KURYRNETS): if not utils.has_kuryr_crd(constants.K8S_API_CRD_KURYRNETS):
@ -253,3 +267,17 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
k8s.annotate(namespace['metadata']['selfLink'], k8s.annotate(namespace['metadata']['selfLink'],
{constants.K8S_ANNOTATION_NAMESPACE_LABEL: annotation}, {constants.K8S_ANNOTATION_NAMESPACE_LABEL: annotation},
resource_version=namespace['metadata']['resourceVersion']) resource_version=namespace['metadata']['resourceVersion'])
def _update_services(self, services, crd_selectors, project_id):
for service in services.get('items'):
if not driver_utils.service_matches_affected_pods(
service, crd_selectors):
continue
sgs = self._drv_svc_sg.get_security_groups(service,
project_id)
self._drv_lbaas.update_lbaas_sg(service, sgs)
def _is_network_policy_enabled(self):
enabled_handlers = oslo_cfg.CONF.kubernetes.enabled_handlers
svc_sg_driver = oslo_cfg.CONF.kubernetes.service_security_groups_driver
return ('policy' in enabled_handlers and svc_sg_driver == 'policy')

View File

@ -64,6 +64,8 @@ class TestNamespaceHandler(test_base.TestCase):
self._handler._drv_sg.create_namespace_sg) self._handler._drv_sg.create_namespace_sg)
self._delete_sg = ( self._delete_sg = (
self._handler._drv_sg.delete_sg) self._handler._drv_sg.delete_sg)
self._delete_namespace_sg_rules = (
self._handler._drv_sg.delete_namespace_sg_rules)
self._cleanup_namespace_networks = ( self._cleanup_namespace_networks = (
self._handler._drv_subnets.cleanup_namespace_networks) self._handler._drv_subnets.cleanup_namespace_networks)
self._get_net_crd = self._handler._get_net_crd self._get_net_crd = self._handler._get_net_crd
@ -94,21 +96,24 @@ class TestNamespaceHandler(test_base.TestCase):
} }
return crd return crd
@mock.patch.object(drivers.LBaaSDriver, 'get_instance')
@mock.patch.object(drivers.VIFPoolDriver, 'get_instance') @mock.patch.object(drivers.VIFPoolDriver, 'get_instance')
@mock.patch.object(drivers.PodSecurityGroupsDriver, 'get_instance') @mock.patch.object(drivers.PodSecurityGroupsDriver, 'get_instance')
@mock.patch.object(drivers.PodSubnetsDriver, 'get_instance') @mock.patch.object(drivers.PodSubnetsDriver, 'get_instance')
@mock.patch.object(drivers.NamespaceProjectDriver, 'get_instance') @mock.patch.object(drivers.NamespaceProjectDriver, 'get_instance')
def test_init(self, m_get_project_driver, m_get_subnets_driver, def test_init(self, m_get_project_driver, m_get_subnets_driver,
m_get_sg_driver, m_get_vif_pool_driver): m_get_sg_driver, m_get_vif_pool_driver, m_get_lbaas_driver):
project_driver = mock.sentinel.project_driver project_driver = mock.sentinel.project_driver
subnets_driver = mock.sentinel.subnets_driver subnets_driver = mock.sentinel.subnets_driver
sg_driver = mock.sentinel.sg_driver sg_driver = mock.sentinel.sg_driver
vif_pool_driver = mock.Mock(spec=vif_pool.MultiVIFPool) vif_pool_driver = mock.Mock(spec=vif_pool.MultiVIFPool)
lbaas_driver = mock.sentinel.lbaas_driver
m_get_project_driver.return_value = project_driver m_get_project_driver.return_value = project_driver
m_get_subnets_driver.return_value = subnets_driver m_get_subnets_driver.return_value = subnets_driver
m_get_sg_driver.return_value = sg_driver m_get_sg_driver.return_value = sg_driver
m_get_vif_pool_driver.return_value = vif_pool_driver m_get_vif_pool_driver.return_value = vif_pool_driver
m_get_lbaas_driver.return_value = lbaas_driver
handler = namespace.NamespaceHandler() handler = namespace.NamespaceHandler()
@ -278,6 +283,7 @@ class TestNamespaceHandler(test_base.TestCase):
self._get_net_crd_id.return_value = net_crd_id self._get_net_crd_id.return_value = net_crd_id
self._get_net_crd.return_value = net_crd self._get_net_crd.return_value = net_crd
self._delete_namespace_sg_rules.return_value = []
namespace.NamespaceHandler.on_deleted(self._handler, self._namespace) namespace.NamespaceHandler.on_deleted(self._handler, self._namespace)