Merge "Add support to match expressions in Network Policies"
This commit is contained in:
commit
fe583c3e6d
|
@ -72,3 +72,8 @@ DEFAULT_IFNAME = 'eth0'
|
|||
|
||||
ADDITIONAL_IFNAME_PREFIX = 'eth'
|
||||
K8S_NPWG_SRIOV_PREFIX = "intel.com/sriov"
|
||||
|
||||
K8S_OPERATOR_IN = 'in'
|
||||
K8S_OPERATOR_NOT_IN = 'notin'
|
||||
K8S_OPERATOR_DOES_NOT_EXIST = 'doesnotexist'
|
||||
K8S_OPERATOR_EXISTS = 'exists'
|
||||
|
|
|
@ -22,6 +22,7 @@ from neutronclient.common import exceptions as n_exc
|
|||
from kuryr_kubernetes import clients
|
||||
from kuryr_kubernetes import constants
|
||||
from kuryr_kubernetes.controller.drivers import base
|
||||
from kuryr_kubernetes.controller.drivers import utils
|
||||
from kuryr_kubernetes import exceptions
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -120,10 +121,7 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
|
|||
'egressSgRules': e_rules,
|
||||
'podSelector': pod_selector,
|
||||
'networkpolicy_spec': policy['spec']})
|
||||
# TODO(ltomasbo): allow patching both spec and metadata in the
|
||||
# same call
|
||||
self.kubernetes.patch('metadata', crd['metadata']['selfLink'],
|
||||
{'labels': pod_selector.get('matchLabels')})
|
||||
|
||||
except exceptions.K8sClientException:
|
||||
LOG.exception('Error updating kuryrnetpolicy CRD %s', crd_name)
|
||||
raise
|
||||
|
@ -443,13 +441,6 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
|
|||
'networkpolicy_spec': policy['spec']
|
||||
},
|
||||
}
|
||||
if pod_selector:
|
||||
try:
|
||||
netpolicy_crd['metadata']['labels'] = pod_selector[
|
||||
'matchLabels']
|
||||
except KeyError:
|
||||
# NOTE(ltomasbo): Only supporting matchLabels for now
|
||||
LOG.info("Pod Selector only allowed with matchLabels")
|
||||
|
||||
try:
|
||||
LOG.debug("Creating KuryrNetPolicy CRD %s" % netpolicy_crd)
|
||||
|
@ -482,18 +473,8 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
|
|||
else:
|
||||
pod_selector = policy['spec'].get('podSelector')
|
||||
if pod_selector:
|
||||
pod_label = pod_selector['matchLabels']
|
||||
pod_namespace = policy['metadata']['namespace']
|
||||
# Removing pod-template-hash as pods will not have it and
|
||||
# otherwise there will be no match
|
||||
pod_label.pop('pod-template-hash', None)
|
||||
pod_label = urlencode(pod_label)
|
||||
# NOTE(ltomasbo): K8s API does not accept &, so we need to AND
|
||||
# the matchLabels with ',' or '%2C' instead
|
||||
pod_label = pod_label.replace('&', ',')
|
||||
pods = self.kubernetes.get(
|
||||
'{}/namespaces/{}/pods?labelSelector={}'.format(
|
||||
constants.K8S_API_BASE, pod_namespace, pod_label))
|
||||
policy_namespace = policy['metadata']['namespace']
|
||||
pods = utils.get_pods(pod_selector, policy_namespace)
|
||||
return pods.get('items')
|
||||
else:
|
||||
# NOTE(ltomasbo): It affects all the pods on the namespace
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
from kuryr_kubernetes import clients
|
||||
from kuryr_kubernetes import config
|
||||
|
@ -26,25 +25,19 @@ from oslo_log import log as logging
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_kuryrnetpolicy_crds(labels=None, namespace='default'):
|
||||
OPERATORS_WITH_VALUES = [constants.K8S_OPERATOR_IN,
|
||||
constants.K8S_OPERATOR_NOT_IN]
|
||||
|
||||
|
||||
def _get_kuryrnetpolicy_crds(namespace='default'):
|
||||
kubernetes = clients.get_kubernetes_client()
|
||||
|
||||
try:
|
||||
if labels:
|
||||
LOG.debug("Using labels %s", labels)
|
||||
labels.pop('pod-template-hash', None)
|
||||
# removing pod-template-hash is necessary to fetch the proper list
|
||||
labels = urlencode(labels)
|
||||
# NOTE(maysams): K8s API does not accept &, so we need to replace
|
||||
# it with ',' or '%2C' instead
|
||||
labels = labels.replace('&', ',')
|
||||
knp_path = '{}/{}/kuryrnetpolicies?labelSelector={}'.format(
|
||||
constants.K8S_API_CRD_NAMESPACES, namespace, labels)
|
||||
LOG.debug("K8s API Query %s", knp_path)
|
||||
knps = kubernetes.get(knp_path)
|
||||
LOG.debug("Return Kuryr Network Policies with label %s", knps)
|
||||
else:
|
||||
knps = kubernetes.get('{}/{}/kuryrnetpolicies'.format(
|
||||
constants.K8S_API_CRD_NAMESPACES, namespace))
|
||||
knp_path = '{}/{}/kuryrnetpolicies'.format(
|
||||
constants.K8S_API_CRD_NAMESPACES, namespace)
|
||||
LOG.debug("K8s API Query %s", knp_path)
|
||||
knps = kubernetes.get(knp_path)
|
||||
LOG.debug("Return Kuryr Network Policies with label %s", knps)
|
||||
except exceptions.K8sResourceNotFound:
|
||||
LOG.exception("KuryrNetPolicy CRD not found")
|
||||
raise
|
||||
|
@ -54,29 +47,76 @@ def _get_kuryrnetpolicy_crds(labels=None, namespace='default'):
|
|||
return knps
|
||||
|
||||
|
||||
def _match_expressions(expressions, pod_labels):
|
||||
for exp in expressions:
|
||||
exp_op = exp['operator'].lower()
|
||||
if pod_labels:
|
||||
if exp_op in OPERATORS_WITH_VALUES:
|
||||
exp_values = exp['values']
|
||||
pod_value = pod_labels.get(str(exp['key']), None)
|
||||
if exp_op == constants.K8S_OPERATOR_IN:
|
||||
if pod_value is None or pod_value not in exp_values:
|
||||
return False
|
||||
elif exp_op == constants.K8S_OPERATOR_NOT_IN:
|
||||
if pod_value in exp_values:
|
||||
return False
|
||||
else:
|
||||
if exp_op == constants.K8S_OPERATOR_EXISTS:
|
||||
exists = pod_labels.get(str(exp['key']), None)
|
||||
if exists is None:
|
||||
return False
|
||||
elif exp_op == constants.K8S_OPERATOR_DOES_NOT_EXIST:
|
||||
exists = pod_labels.get(str(exp['key']), None)
|
||||
if exists is not None:
|
||||
return False
|
||||
else:
|
||||
if exp_op in (constants.K8S_OPERATOR_IN,
|
||||
constants.K8S_OPERATOR_EXISTS):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _match_labels(crd_labels, pod_labels):
|
||||
for label_key, label_value in crd_labels.items():
|
||||
pod_value = pod_labels.get(label_key, None)
|
||||
if not pod_value or label_value != pod_value:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
|
||||
"""Provides security groups for pods based on network policies"""
|
||||
|
||||
def get_security_groups(self, pod, project_id):
|
||||
sg_list = []
|
||||
pod_namespace = pod['metadata']['namespace']
|
||||
|
||||
pod_labels = pod['metadata'].get('labels')
|
||||
LOG.debug("Using labels %s", pod_labels)
|
||||
pod_namespace = pod['metadata']['namespace']
|
||||
|
||||
if pod_labels:
|
||||
knp_crds = _get_kuryrnetpolicy_crds(pod_labels,
|
||||
namespace=pod_namespace)
|
||||
for crd in knp_crds.get('items'):
|
||||
knp_crds = _get_kuryrnetpolicy_crds(namespace=pod_namespace)
|
||||
for crd in knp_crds.get('items'):
|
||||
pod_selector = crd['spec'].get('podSelector')
|
||||
if pod_selector:
|
||||
crd_labels = pod_selector.get('matchLabels', None)
|
||||
crd_expressions = pod_selector.get('matchExpressions', None)
|
||||
|
||||
match_exp = match_lb = True
|
||||
if crd_expressions:
|
||||
match_exp = _match_expressions(crd_expressions,
|
||||
pod_labels)
|
||||
if crd_labels and pod_labels:
|
||||
match_lb = _match_labels(crd_labels, pod_labels)
|
||||
if match_exp and match_lb:
|
||||
LOG.debug("Appending %s",
|
||||
str(crd['spec']['securityGroupId']))
|
||||
sg_list.append(str(crd['spec']['securityGroupId']))
|
||||
else:
|
||||
LOG.debug("Appending %s", str(crd['spec']['securityGroupId']))
|
||||
sg_list.append(str(crd['spec']['securityGroupId']))
|
||||
|
||||
knp_namespace_crds = _get_kuryrnetpolicy_crds(namespace=pod_namespace)
|
||||
for crd in knp_namespace_crds.get('items'):
|
||||
if not crd['metadata'].get('labels'):
|
||||
LOG.debug("Appending %s", str(crd['spec']['securityGroupId']))
|
||||
sg_list.append(str(crd['spec']['securityGroupId']))
|
||||
|
||||
if not knp_namespace_crds.get('items') and not sg_list:
|
||||
# NOTE(maysams) Pods that are not selected by any Networkpolicy
|
||||
# are fully accessible. Thus, the default security group is associated.
|
||||
if not sg_list:
|
||||
sg_list = config.CONF.neutron_defaults.pod_security_groups
|
||||
if not sg_list:
|
||||
raise cfg.RequiredOptError('pod_security_groups',
|
||||
|
@ -104,20 +144,30 @@ class NetworkPolicyServiceSecurityGroupsDriver(
|
|||
svc_labels = service['metadata'].get('labels')
|
||||
LOG.debug("Using labels %s", svc_labels)
|
||||
|
||||
if svc_labels:
|
||||
knp_crds = _get_kuryrnetpolicy_crds(svc_labels,
|
||||
namespace=svc_namespace)
|
||||
for crd in knp_crds.get('items'):
|
||||
knp_crds = _get_kuryrnetpolicy_crds(namespace=svc_namespace)
|
||||
for crd in knp_crds.get('items'):
|
||||
pod_selector = crd['spec'].get('podSelector')
|
||||
if pod_selector:
|
||||
crd_labels = pod_selector.get('matchLabels', None)
|
||||
crd_expressions = pod_selector.get('matchExpressions', None)
|
||||
|
||||
match_exp = match_lb = True
|
||||
if crd_expressions:
|
||||
match_exp = _match_expressions(crd_expressions,
|
||||
svc_labels)
|
||||
if crd_labels and svc_labels:
|
||||
match_lb = _match_labels(crd_labels, svc_labels)
|
||||
if match_exp and match_lb:
|
||||
LOG.debug("Appending %s",
|
||||
str(crd['spec']['securityGroupId']))
|
||||
sg_list.append(str(crd['spec']['securityGroupId']))
|
||||
else:
|
||||
LOG.debug("Appending %s", str(crd['spec']['securityGroupId']))
|
||||
sg_list.append(str(crd['spec']['securityGroupId']))
|
||||
|
||||
knp_namespace_crds = _get_kuryrnetpolicy_crds(namespace=svc_namespace)
|
||||
for crd in knp_namespace_crds.get('items'):
|
||||
if not crd['metadata'].get('labels'):
|
||||
LOG.debug("Appending %s", str(crd['spec']['securityGroupId']))
|
||||
sg_list.append(str(crd['spec']['securityGroupId']))
|
||||
|
||||
if not knp_namespace_crds.get('items') and not sg_list:
|
||||
# NOTE(maysams) Pods that are not selected by any Networkpolicy
|
||||
# are fully accessible. Thus, the default security group is associated.
|
||||
if not sg_list:
|
||||
sg_list = config.CONF.neutron_defaults.pod_security_groups
|
||||
if not sg_list:
|
||||
raise cfg.RequiredOptError('pod_security_groups',
|
||||
|
|
|
@ -14,12 +14,17 @@
|
|||
# under the License.
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from kuryr_kubernetes import clients
|
||||
from kuryr_kubernetes import constants
|
||||
from kuryr_kubernetes import exceptions as k_exc
|
||||
from kuryr_kubernetes import os_vif_util as ovu
|
||||
from kuryr_kubernetes import utils
|
||||
|
||||
OPERATORS_WITH_VALUES = [constants.K8S_OPERATOR_IN,
|
||||
constants.K8S_OPERATOR_NOT_IN]
|
||||
|
||||
|
||||
def get_network_id(subnets):
|
||||
ids = ovu.osvif_to_neutron_network_ids(subnets)
|
||||
|
@ -58,3 +63,51 @@ def get_pod_state(pod):
|
|||
|
||||
def is_host_network(pod):
|
||||
return pod['spec'].get('hostNetwork', False)
|
||||
|
||||
|
||||
def get_pods(selector, namespace):
|
||||
kubernetes = clients.get_kubernetes_client()
|
||||
labels = selector.get('matchLabels', None)
|
||||
if labels:
|
||||
# Removing pod-template-hash as pods will not have it and
|
||||
# otherwise there will be no match
|
||||
labels.pop('pod-template-hash', None)
|
||||
labels = replace_encoded_characters(labels)
|
||||
|
||||
exps = selector.get('matchExpressions', None)
|
||||
if exps:
|
||||
exps = ', '.join(format_expression(exp) for exp in exps)
|
||||
if labels:
|
||||
expressions = parse.quote("," + exps)
|
||||
labels += expressions
|
||||
else:
|
||||
labels = parse.quote(exps)
|
||||
|
||||
pods = kubernetes.get(
|
||||
'{}/namespaces/{}/pods?labelSelector={}'.format(
|
||||
constants.K8S_API_BASE, namespace, labels))
|
||||
|
||||
return pods
|
||||
|
||||
|
||||
def format_expression(expression):
|
||||
key = expression['key']
|
||||
operator = expression['operator'].lower()
|
||||
if operator in OPERATORS_WITH_VALUES:
|
||||
values = expression['values']
|
||||
values = str(', '.join(values))
|
||||
values = "(%s)" % values
|
||||
return "%s %s %s" % (key, operator, values)
|
||||
else:
|
||||
if operator == constants.K8S_OPERATOR_DOES_NOT_EXIST:
|
||||
return "!%s" % key
|
||||
else:
|
||||
return key
|
||||
|
||||
|
||||
def replace_encoded_characters(labels):
|
||||
labels = parse.urlencode(labels)
|
||||
# NOTE(ltomasbo): K8s API does not accept &, so we need to AND
|
||||
# the matchLabels with ',' or '%2C' instead
|
||||
labels = labels.replace('&', ',')
|
||||
return labels
|
||||
|
|
|
@ -61,12 +61,6 @@ class NetworkPolicyHandler(k8s_base.ResourceEventHandler):
|
|||
project_id = self._drv_project.get_project(policy)
|
||||
pods_to_update = []
|
||||
|
||||
knps_on_namespace = self._drv_policy.knps_on_namespace(
|
||||
policy['metadata']['namespace'])
|
||||
if not knps_on_namespace:
|
||||
namespace_pods = self._drv_policy.namespaced_pods(policy)
|
||||
pods_to_update.extend(namespace_pods)
|
||||
|
||||
modified_pods = self._drv_policy.ensure_network_policy(policy,
|
||||
project_id)
|
||||
if modified_pods:
|
||||
|
@ -89,18 +83,15 @@ class NetworkPolicyHandler(k8s_base.ResourceEventHandler):
|
|||
pod_sgs = self._drv_pod_sg.get_security_groups(pod, project_id)
|
||||
if crd_sg in pod_sgs:
|
||||
pod_sgs.remove(crd_sg)
|
||||
if not pod_sgs:
|
||||
pod_sgs = oslo_cfg.CONF.neutron_defaults.pod_security_groups
|
||||
if not pod_sgs:
|
||||
raise oslo_cfg.RequiredOptError('pod_security_groups',
|
||||
oslo_cfg.OptGroup(
|
||||
'neutron_defaults'))
|
||||
self._drv_vif_pool.update_vif_sgs(pod, pod_sgs)
|
||||
|
||||
self._drv_policy.release_network_policy(netpolicy_crd)
|
||||
# re-apply original security groups for the namespace
|
||||
knps_on_namespace = self._drv_policy.knps_on_namespace(
|
||||
policy['metadata']['namespace'])
|
||||
if not knps_on_namespace:
|
||||
namespace_pods = self._drv_policy.namespaced_pods(policy)
|
||||
for pod in namespace_pods:
|
||||
pod_sgs = self._drv_pod_sg.get_security_groups(pod,
|
||||
project_id)
|
||||
self._drv_vif_pool.update_vif_sgs(pod, pod_sgs)
|
||||
|
||||
@MEMOIZE
|
||||
def is_ready(self, quota):
|
||||
|
|
|
@ -25,9 +25,9 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
|
|||
|
||||
def setUp(self):
|
||||
super(TestNetworkPolicySecurityGroupsDriver, self).setUp()
|
||||
self._labels = mock.sentinel.labels
|
||||
self._project_id = mock.sentinel.project_id
|
||||
self._sg_id = mock.sentinel.sg_id
|
||||
self._sg_id2 = mock.sentinel._sg_id2
|
||||
self._namespace = 'default'
|
||||
self._crd = {
|
||||
'metadata': {'name': mock.sentinel.name,
|
||||
|
@ -55,9 +55,38 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
|
|||
'security_group_id': self._sg_id,
|
||||
'id': mock.sentinel.id
|
||||
}}],
|
||||
'podSelector': {
|
||||
'matchExpressions': [
|
||||
{
|
||||
'key': 'environment',
|
||||
'operator': 'In',
|
||||
'values': [
|
||||
'production']}],
|
||||
'matchLabels': {
|
||||
'run': 'demo'
|
||||
}},
|
||||
'securityGroupId': self._sg_id,
|
||||
'securityGroupName': mock.sentinel.sg_name}}
|
||||
|
||||
self._crd2 = {
|
||||
'metadata': {'name': mock.sentinel.name3,
|
||||
'selfLink': mock.sentinel.selfLink},
|
||||
'spec': {
|
||||
'ingressSgRules': [
|
||||
{'security_group_rule':
|
||||
{'description': 'Kuryr-Kubernetes NetPolicy SG rule',
|
||||
'direction': 'ingress',
|
||||
'ethertype': 'IPv4',
|
||||
'port_range_max': 8080,
|
||||
'port_range_min': 8080,
|
||||
'protocol': 'tcp',
|
||||
'security_group_id': self._sg_id2,
|
||||
'id': mock.sentinel.id
|
||||
}}],
|
||||
'podSelector': {},
|
||||
'securityGroupId': self._sg_id2,
|
||||
'securityGroupName': mock.sentinel.sg_name}}
|
||||
|
||||
self._crds = {
|
||||
"apiVersion": "v1",
|
||||
"items": [self._crd],
|
||||
|
@ -66,6 +95,14 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
|
|||
"resourceVersion": "",
|
||||
"selfLink": mock.sentinel.selfLink}}
|
||||
|
||||
self._multiple_crds = {
|
||||
"apiVersion": "v1",
|
||||
"items": [self._crd, self._crd2],
|
||||
"kind": "List",
|
||||
"metadata": {
|
||||
"resourceVersion": "",
|
||||
"selfLink": mock.sentinel.selfLink}}
|
||||
|
||||
self._empty_crds = {
|
||||
"apiVersion": "v1",
|
||||
"items": [],
|
||||
|
@ -81,7 +118,39 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
|
|||
'name': mock.sentinel.pod_name,
|
||||
'namespace': self._namespace,
|
||||
'labels': {
|
||||
'run': 'demo'}},
|
||||
'run': 'demo',
|
||||
'environment': 'production'}},
|
||||
'spec': {
|
||||
'containers': [{
|
||||
'image': 'kuryr/demo',
|
||||
'imagePullPolicy': 'Always',
|
||||
'name': mock.sentinel.pod_name
|
||||
}]
|
||||
}}
|
||||
|
||||
self._pod2 = {
|
||||
'apiVersion': 'v1',
|
||||
'kind': 'Pod',
|
||||
'metadata': {
|
||||
'name': mock.sentinel.pod_name,
|
||||
'namespace': self._namespace,
|
||||
'labels': {
|
||||
'run': 'demo',
|
||||
'environment': 'development'}},
|
||||
'spec': {
|
||||
'containers': [{
|
||||
'image': 'kuryr/demo',
|
||||
'imagePullPolicy': 'Always',
|
||||
'name': mock.sentinel.pod_name
|
||||
}]
|
||||
}}
|
||||
|
||||
self._pod_without_label = {
|
||||
'apiVersion': 'v1',
|
||||
'kind': 'Pod',
|
||||
'metadata': {
|
||||
'name': mock.sentinel.pod_name,
|
||||
'namespace': self._namespace},
|
||||
'spec': {
|
||||
'containers': [{
|
||||
'image': 'kuryr/demo',
|
||||
|
@ -94,35 +163,92 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
|
|||
self._driver = (
|
||||
network_policy_security_groups.NetworkPolicySecurityGroupsDriver())
|
||||
|
||||
@mock.patch('kuryr_kubernetes.config.CONF')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_get_kuryrnetpolicy_crds')
|
||||
def test_get_security_groups(self, m_get_crds):
|
||||
def test_get_sgs_for_pod_without_label(self, m_get_crds, m_cfg):
|
||||
m_get_crds.return_value = self._crds
|
||||
self._driver.get_security_groups(self._pod, self._project_id)
|
||||
calls = [mock.call(self._pod['metadata']['labels'],
|
||||
namespace=self._namespace),
|
||||
mock.call(namespace=self._namespace)]
|
||||
m_get_crds.assert_has_calls(calls)
|
||||
sg_list = [str(mock.sentinel.sg_id)]
|
||||
m_cfg.neutron_defaults.pod_security_groups = sg_list
|
||||
|
||||
sgs = self._driver.get_security_groups(self._pod_without_label,
|
||||
self._project_id)
|
||||
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_get_kuryrnetpolicy_crds')
|
||||
def test_get_security_groups_without_label(self, m_get_crds):
|
||||
pod = self._pod.copy()
|
||||
del pod['metadata']['labels']
|
||||
labels = {'run': 'demo'}
|
||||
self._crds['items'][0]['metadata']['labels'] = labels
|
||||
m_get_crds.return_value = self._crds
|
||||
self._driver.get_security_groups(pod, self._project_id)
|
||||
m_get_crds.assert_called_once_with(namespace=self._namespace)
|
||||
self.assertEqual(sg_list, sgs)
|
||||
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_match_expressions')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_match_labels')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_get_kuryrnetpolicy_crds')
|
||||
def test_get_sgs_for_pod_with_label(self, m_get_crds, m_match_labels,
|
||||
m_match_expressions):
|
||||
m_get_crds.return_value = self._crds
|
||||
m_match_expressions.return_value = True
|
||||
m_match_labels.return_value = True
|
||||
pod_labels = self._pod['metadata']['labels']
|
||||
resp = self._driver.get_security_groups(self._pod, self._project_id)
|
||||
|
||||
m_get_crds.assert_called_once_with(namespace=self._namespace)
|
||||
m_match_expressions.assert_called_once_with(
|
||||
self._crd['spec']['podSelector']['matchExpressions'], pod_labels)
|
||||
m_match_labels.assert_called_once_with(
|
||||
self._crd['spec']['podSelector']['matchLabels'], pod_labels)
|
||||
self.assertEqual(resp, [str(self._sg_id)])
|
||||
|
||||
@mock.patch('kuryr_kubernetes.config.CONF')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_match_expressions')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_match_labels')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_get_kuryrnetpolicy_crds')
|
||||
def test_get_sgs_for_pod_with_label_no_match(self, m_get_crds,
|
||||
m_match_labels,
|
||||
m_match_expressions, m_cfg):
|
||||
m_get_crds.return_value = self._crds
|
||||
m_match_expressions.return_value = False
|
||||
m_match_labels.return_value = True
|
||||
sg_list = [mock.sentinel.sg_id]
|
||||
m_cfg.neutron_defaults.pod_security_groups = sg_list
|
||||
pod_labels = self._pod2['metadata']['labels']
|
||||
|
||||
sgs = self._driver.get_security_groups(self._pod2, self._project_id)
|
||||
|
||||
m_get_crds.assert_called_once_with(namespace=self._namespace)
|
||||
m_match_expressions.assert_called_once_with(
|
||||
self._crd['spec']['podSelector']['matchExpressions'], pod_labels)
|
||||
m_match_labels.assert_called_once_with(
|
||||
self._crd['spec']['podSelector']['matchLabels'], pod_labels)
|
||||
self.assertEqual(sg_list, sgs)
|
||||
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_get_kuryrnetpolicy_crds')
|
||||
def test_get_security_groups_no_crds(self, m_get_crds):
|
||||
def test_get_sgs_no_crds(self, m_get_crds):
|
||||
m_get_crds.return_value = self._empty_crds
|
||||
cfg.CONF.set_override('pod_security_groups', [],
|
||||
group='neutron_defaults')
|
||||
|
||||
self.assertRaises(cfg.RequiredOptError,
|
||||
self._driver.get_security_groups, self._pod,
|
||||
self._project_id)
|
||||
calls = [mock.call(self._pod['metadata']['labels'],
|
||||
namespace=self._namespace),
|
||||
mock.call(namespace=self._namespace)]
|
||||
m_get_crds.assert_has_calls(calls)
|
||||
m_get_crds.assert_called_with(namespace=self._namespace)
|
||||
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_match_expressions')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_match_labels')
|
||||
@mock.patch.object(network_policy_security_groups,
|
||||
'_get_kuryrnetpolicy_crds')
|
||||
def test_get_sgs_multiple_crds(self, m_get_crds, m_match_labels,
|
||||
m_match_expressions):
|
||||
m_match_expressions.return_value = True
|
||||
m_match_labels.return_value = True
|
||||
m_get_crds.return_value = self._multiple_crds
|
||||
|
||||
resp = self._driver.get_security_groups(self._pod, self._project_id)
|
||||
|
||||
m_get_crds.assert_called_once_with(namespace=self._namespace)
|
||||
self.assertEqual([str(self._sg_id), str(self._sg_id2)], resp)
|
||||
|
|
|
@ -139,34 +139,25 @@ class TestPolicyHandler(test_base.TestCase):
|
|||
def test_on_present_without_knps_on_namespace(self):
|
||||
modified_pod = mock.sentinel.modified_pod
|
||||
match_pod = mock.sentinel.match_pod
|
||||
namespace_pod = mock.sentinel.namespace_pod
|
||||
|
||||
knp_on_ns = self._handler._drv_policy.knps_on_namespace
|
||||
knp_on_ns.return_value = False
|
||||
namespaced_pods = self._handler._drv_policy.namespaced_pods
|
||||
namespaced_pods.return_value = [namespace_pod]
|
||||
ensure_nw_policy = self._handler._drv_policy.ensure_network_policy
|
||||
ensure_nw_policy.return_value = [modified_pod]
|
||||
affected_pods = self._handler._drv_policy.affected_pods
|
||||
affected_pods.return_value = [match_pod]
|
||||
sg1 = [mock.sentinel.sg1]
|
||||
sg2 = [mock.sentinel.sg2]
|
||||
sg3 = [mock.sentinel.sg3]
|
||||
self._get_security_groups.side_effect = [sg1, sg2, sg3]
|
||||
self._get_security_groups.side_effect = [sg2, sg3]
|
||||
|
||||
policy.NetworkPolicyHandler.on_present(self._handler, self._policy)
|
||||
namespaced_pods.assert_called_once_with(self._policy)
|
||||
ensure_nw_policy.assert_called_once_with(self._policy,
|
||||
self._project_id)
|
||||
affected_pods.assert_called_once_with(self._policy)
|
||||
|
||||
calls = [mock.call(namespace_pod, self._project_id),
|
||||
mock.call(modified_pod, self._project_id),
|
||||
calls = [mock.call(modified_pod, self._project_id),
|
||||
mock.call(match_pod, self._project_id)]
|
||||
self._get_security_groups.assert_has_calls(calls)
|
||||
|
||||
calls = [mock.call(namespace_pod, sg1),
|
||||
mock.call(modified_pod, sg2),
|
||||
calls = [mock.call(modified_pod, sg2),
|
||||
mock.call(match_pod, sg3)]
|
||||
self._update_vif_sgs.assert_has_calls(calls)
|
||||
|
||||
|
@ -189,8 +180,6 @@ class TestPolicyHandler(test_base.TestCase):
|
|||
|
||||
policy.NetworkPolicyHandler.on_deleted(self._handler, self._policy)
|
||||
release_nw_policy.assert_called_once_with(knp_obj)
|
||||
calls = [mock.call(match_pod, self._project_id),
|
||||
mock.call(namespace_pod, self._project_id)]
|
||||
self._get_security_groups.assert_has_calls(calls)
|
||||
calls = [mock.call(match_pod, sg1), mock.call(namespace_pod, sg2)]
|
||||
self._update_vif_sgs.assert_has_calls(calls)
|
||||
self._get_security_groups.assert_called_once_with(match_pod,
|
||||
self._project_id)
|
||||
self._update_vif_sgs.assert_called_once_with(match_pod, sg1)
|
||||
|
|
Loading…
Reference in New Issue