summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaysa Macedo <maysa.macedo95@gmail.com>2018-12-30 22:10:51 +0000
committerMaysa Macedo <maysa.macedo95@gmail.com>2019-01-08 20:22:02 +0000
commit9deb322962605bb1fad11a25ea30c6af5d73a385 (patch)
tree69c5dcc199c34cae63f125d5dffc45c16d5e95af
parent7480cc36f8b33d881089fe1c82ec3c65983452f6 (diff)
Update CRD when NP has namespaceSelectors
When a namespace is created, deleted or updated and its labels matches the namespaceSelector of a NP, the CRD and the respective sg must be updated. Partially Implements: blueprint k8s-network-policies Change-Id: I515de28647f5f06248555733c27dd4f5a56149ec
Notes
Notes (review): Code-Review+2: Daniel Mellado <dmellado@redhat.com> Code-Review+2: Michał Dulko <mdulko@redhat.com> Workflow+1: Michał Dulko <mdulko@redhat.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Wed, 09 Jan 2019 12:45:30 +0000 Reviewed-on: https://review.openstack.org/627850 Project: openstack/kuryr-kubernetes Branch: refs/heads/master
-rw-r--r--kuryr_kubernetes/constants.py1
-rw-r--r--kuryr_kubernetes/controller/drivers/base.py21
-rw-r--r--kuryr_kubernetes/controller/drivers/default_security_groups.py12
-rw-r--r--kuryr_kubernetes/controller/drivers/namespace_security_groups.py130
-rw-r--r--kuryr_kubernetes/controller/drivers/network_policy.py35
-rw-r--r--kuryr_kubernetes/controller/drivers/network_policy_security_groups.py131
-rw-r--r--kuryr_kubernetes/controller/drivers/utils.py103
-rw-r--r--kuryr_kubernetes/controller/handlers/namespace.py30
-rw-r--r--kuryr_kubernetes/tests/unit/controller/drivers/test_namespace_security_groups.py265
-rw-r--r--kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy.py12
-rw-r--r--kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy_security_groups.py70
11 files changed, 643 insertions, 167 deletions
diff --git a/kuryr_kubernetes/constants.py b/kuryr_kubernetes/constants.py
index b579033..4e8999f 100644
--- a/kuryr_kubernetes/constants.py
+++ b/kuryr_kubernetes/constants.py
@@ -37,6 +37,7 @@ K8S_POD_STATUS_PENDING = 'Pending'
37K8S_ANNOTATION_PREFIX = 'openstack.org/kuryr' 37K8S_ANNOTATION_PREFIX = 'openstack.org/kuryr'
38K8S_ANNOTATION_VIF = K8S_ANNOTATION_PREFIX + '-vif' 38K8S_ANNOTATION_VIF = K8S_ANNOTATION_PREFIX + '-vif'
39K8S_ANNOTATION_LABEL = K8S_ANNOTATION_PREFIX + '-pod-label' 39K8S_ANNOTATION_LABEL = K8S_ANNOTATION_PREFIX + '-pod-label'
40K8S_ANNOTATION_NAMESPACE_LABEL = K8S_ANNOTATION_PREFIX + '-namespace-label'
40K8S_ANNOTATION_LBAAS_SPEC = K8S_ANNOTATION_PREFIX + '-lbaas-spec' 41K8S_ANNOTATION_LBAAS_SPEC = K8S_ANNOTATION_PREFIX + '-lbaas-spec'
41K8S_ANNOTATION_LBAAS_STATE = K8S_ANNOTATION_PREFIX + '-lbaas-state' 42K8S_ANNOTATION_LBAAS_STATE = K8S_ANNOTATION_PREFIX + '-lbaas-state'
42K8S_ANNOTATION_NET_CRD = K8S_ANNOTATION_PREFIX + '-net-crd' 43K8S_ANNOTATION_NET_CRD = K8S_ANNOTATION_PREFIX + '-net-crd'
diff --git a/kuryr_kubernetes/controller/drivers/base.py b/kuryr_kubernetes/controller/drivers/base.py
index 765e3dd..d557436 100644
--- a/kuryr_kubernetes/controller/drivers/base.py
+++ b/kuryr_kubernetes/controller/drivers/base.py
@@ -268,6 +268,27 @@ class PodSecurityGroupsDriver(DriverBase):
268 """ 268 """
269 raise NotImplementedError() 269 raise NotImplementedError()
270 270
271 def delete_namespace_sg_rules(self, namespace):
272 """Delete security group rule associated to a namespace.
273
274 :param namespace: dict containing K8S Namespace object
275 """
276 raise NotImplementedError()
277
278 def create_namespace_sg_rules(self, namespace):
279 """Create security group rule associated to a namespace.
280
281 :param namespace: dict containing K8S Namespace object
282 """
283 raise NotImplementedError()
284
285 def update_namespace_sg_rules(self, namespace):
286 """Update security group rule associated to a namespace.
287
288 :param namespace: dict containing K8S Namespace object
289 """
290 raise NotImplementedError()
291
271 292
272@six.add_metaclass(abc.ABCMeta) 293@six.add_metaclass(abc.ABCMeta)
273class ServiceSecurityGroupsDriver(DriverBase): 294class ServiceSecurityGroupsDriver(DriverBase):
diff --git a/kuryr_kubernetes/controller/drivers/default_security_groups.py b/kuryr_kubernetes/controller/drivers/default_security_groups.py
index 0a4dd95..432af0d 100644
--- a/kuryr_kubernetes/controller/drivers/default_security_groups.py
+++ b/kuryr_kubernetes/controller/drivers/default_security_groups.py
@@ -59,6 +59,18 @@ class DefaultPodSecurityGroupsDriver(base.PodSecurityGroupsDriver):
59 LOG.debug("Security group driver does not update SG rules for " 59 LOG.debug("Security group driver does not update SG rules for "
60 "the pods.") 60 "the pods.")
61 61
62 def delete_namespace_sg_rules(self, namespace):
63 LOG.debug("Security group driver does not delete SG rules for "
64 "namespace.")
65
66 def create_namespace_sg_rules(self, namespace):
67 LOG.debug("Security group driver does not create SG rules for "
68 "namespace.")
69
70 def update_namespace_sg_rules(self, namespace):
71 LOG.debug("Security group driver does not update SG rules for "
72 "namespace.")
73
62 74
63class DefaultServiceSecurityGroupsDriver(base.ServiceSecurityGroupsDriver): 75class DefaultServiceSecurityGroupsDriver(base.ServiceSecurityGroupsDriver):
64 """Provides security groups for Service based on a configuration option.""" 76 """Provides security groups for Service based on a configuration option."""
diff --git a/kuryr_kubernetes/controller/drivers/namespace_security_groups.py b/kuryr_kubernetes/controller/drivers/namespace_security_groups.py
index 3e25b56..e4e2b87 100644
--- a/kuryr_kubernetes/controller/drivers/namespace_security_groups.py
+++ b/kuryr_kubernetes/controller/drivers/namespace_security_groups.py
@@ -21,6 +21,7 @@ from kuryr_kubernetes import clients
21from kuryr_kubernetes import config 21from kuryr_kubernetes import config
22from kuryr_kubernetes import constants 22from kuryr_kubernetes import constants
23from kuryr_kubernetes.controller.drivers import base 23from kuryr_kubernetes.controller.drivers import base
24from kuryr_kubernetes.controller.drivers import utils
24from kuryr_kubernetes import exceptions 25from kuryr_kubernetes import exceptions
25 26
26from neutronclient.common import exceptions as n_exc 27from neutronclient.common import exceptions as n_exc
@@ -67,6 +68,73 @@ def _get_net_crd(namespace):
67 return net_crd 68 return net_crd
68 69
69 70
71def _create_sg_rule(sg_id, direction, cidr, port=None, namespace=None):
72 if port:
73 sg_rule = utils.create_security_group_rule_body(
74 sg_id, direction, port.get('port'),
75 protocol=port.get('protocol'), cidr=cidr, namespace=namespace)
76 else:
77 sg_rule = utils.create_security_group_rule_body(
78 sg_id, direction, port_range_min=1,
79 port_range_max=65535, cidr=cidr, namespace=namespace)
80
81 sgr_id = utils.create_security_group_rule(sg_rule)
82
83 sg_rule['security_group_rule']['id'] = sgr_id
84 return sg_rule
85
86
87def _parse_rules(direction, crd, namespace):
88 policy = crd['spec']['networkpolicy_spec']
89 sg_id = crd['spec']['securityGroupId']
90
91 ns_labels = namespace['metadata'].get('labels')
92 ns_name = namespace['metadata'].get('name')
93 ns_cidr = utils.get_namespace_subnet_cidr(namespace)
94
95 rule_direction = 'from'
96 crd_rules = crd['spec'].get('ingressSgRules')
97 if direction == 'egress':
98 rule_direction = 'to'
99 crd_rules = crd['spec'].get('egressSgRules')
100
101 matched = False
102 rule_list = policy.get(direction, None)
103 for rule_block in rule_list:
104 for rule in rule_block.get(rule_direction, []):
105 pod_selector = rule.get('podSelector')
106 ns_selector = rule.get('namespaceSelector')
107 if (ns_selector and ns_labels and
108 utils.match_selector(ns_selector, ns_labels)):
109 if pod_selector:
110 pods = utils.get_pods(pod_selector, ns_name)
111 for pod in pods.get('items'):
112 pod_ip = utils.get_pod_ip(pod)
113 if 'ports' in rule_block:
114 for port in rule_block['ports']:
115 matched = True
116 crd_rules.append(_create_sg_rule(
117 sg_id, direction, pod_ip, port=port,
118 namespace=ns_name))
119 else:
120 matched = True
121 crd_rules.append(_create_sg_rule(
122 sg_id, direction, pod_ip,
123 namespace=ns_name))
124 else:
125 if 'ports' in rule_block:
126 for port in rule_block['ports']:
127 matched = True
128 crd_rules.append(_create_sg_rule(
129 sg_id, direction, ns_cidr,
130 port=port, namespace=ns_name))
131 else:
132 matched = True
133 crd_rules.append(_create_sg_rule(
134 sg_id, direction, ns_cidr, namespace=ns_name))
135 return matched, crd_rules
136
137
70class NamespacePodSecurityGroupsDriver(base.PodSecurityGroupsDriver): 138class NamespacePodSecurityGroupsDriver(base.PodSecurityGroupsDriver):
71 """Provides security groups for Pod based on a configuration option.""" 139 """Provides security groups for Pod based on a configuration option."""
72 140
@@ -131,6 +199,68 @@ class NamespacePodSecurityGroupsDriver(base.PodSecurityGroupsDriver):
131 LOG.exception("Error deleting security group %s.", sg_id) 199 LOG.exception("Error deleting security group %s.", sg_id)
132 raise 200 raise
133 201
202 def delete_namespace_sg_rules(self, namespace):
203 ns_name = namespace['metadata']['name']
204 LOG.debug("Deleting sg rule for namespace: %s",
205 ns_name)
206
207 knp_crds = utils.get_kuryrnetpolicy_crds()
208 for crd in knp_crds.get('items'):
209 crd_selector = crd['spec'].get('podSelector')
210 ingress_rule_list = crd['spec'].get('ingressSgRules')
211 egress_rule_list = crd['spec'].get('egressSgRules')
212 i_rules = []
213 e_rules = []
214
215 matched = False
216 for i_rule in ingress_rule_list:
217 LOG.debug("Parsing ingress rule: %r", i_rule)
218 rule_namespace = i_rule.get('namespace', None)
219
220 if rule_namespace and rule_namespace == ns_name:
221 matched = True
222 utils.delete_security_group_rule(
223 i_rule['security_group_rule']['id'])
224 else:
225 i_rules.append(i_rule)
226
227 for e_rule in egress_rule_list:
228 LOG.debug("Parsing egress rule: %r", e_rule)
229 rule_namespace = e_rule.get('namespace', None)
230
231 if rule_namespace and rule_namespace == ns_name:
232 matched = True
233 utils.delete_security_group_rule(
234 e_rule['security_group_rule']['id'])
235 else:
236 e_rules.append(e_rule)
237
238 if matched:
239 utils.patch_kuryr_crd(crd, i_rules, e_rules, crd_selector)
240
241 def create_namespace_sg_rules(self, namespace):
242 kubernetes = clients.get_kubernetes_client()
243 ns_name = namespace['metadata']['name']
244 LOG.debug("Creating sg rule for namespace: %s", ns_name)
245 namespace = kubernetes.get(
246 '{}/namespaces/{}'.format(constants.K8S_API_BASE, ns_name))
247 knp_crds = utils.get_kuryrnetpolicy_crds()
248 for crd in knp_crds.get('items'):
249 crd_selector = crd['spec'].get('podSelector')
250
251 i_matched, i_rules = _parse_rules('ingress', crd, namespace)
252 e_matched, e_rules = _parse_rules('egress', crd, namespace)
253
254 if i_matched or e_matched:
255 utils.patch_kuryr_crd(crd, i_rules,
256 e_rules, crd_selector)
257
258 def update_namespace_sg_rules(self, namespace):
259 LOG.debug("Updating sg rule for namespace: %s",
260 namespace['metadata']['name'])
261 self.delete_namespace_sg_rules(namespace)
262 self.create_namespace_sg_rules(namespace)
263
134 def create_sg_rules(self, pod): 264 def create_sg_rules(self, pod):
135 LOG.debug("Security group driver does not create SG rules for " 265 LOG.debug("Security group driver does not create SG rules for "
136 "the pods.") 266 "the pods.")
diff --git a/kuryr_kubernetes/controller/drivers/network_policy.py b/kuryr_kubernetes/controller/drivers/network_policy.py
index 2f1e07f..3b75930 100644
--- a/kuryr_kubernetes/controller/drivers/network_policy.py
+++ b/kuryr_kubernetes/controller/drivers/network_policy.py
@@ -203,40 +203,27 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
203 matching_pods = driver_utils.get_pods(pod_selector, namespace) 203 matching_pods = driver_utils.get_pods(pod_selector, namespace)
204 for pod in matching_pods.get('items'): 204 for pod in matching_pods.get('items'):
205 if pod['status']['podIP']: 205 if pod['status']['podIP']:
206 ips.append(pod['status']['podIP']) 206 pod_ip = pod['status']['podIP']
207 ns = pod['metadata']['namespace']
208 ips.append({'cidr': pod_ip, 'namespace': ns})
207 return ips 209 return ips
208 210
209 def _get_namespace_subnet_cidr(self, namespace):
210 try:
211 ns_annotations = namespace['metadata']['annotations']
212 ns_name = ns_annotations[constants.K8S_ANNOTATION_NET_CRD]
213 except KeyError:
214 LOG.exception('Namespace handler must be enabled to support '
215 'Network Policies with namespaceSelector')
216 raise exceptions.ResourceNotReady(namespace)
217 try:
218 net_crd = self.kubernetes.get('{}/kuryrnets/{}'.format(
219 constants.K8S_API_CRD, ns_name))
220 except exceptions.K8sClientException:
221 LOG.exception("Kubernetes Client Exception.")
222 raise
223 return net_crd['spec']['subnetCIDR']
224
225 def _get_namespaces_cidr(self, namespace_selector, namespace=None): 211 def _get_namespaces_cidr(self, namespace_selector, namespace=None):
226 cidrs = [] 212 cidrs = []
227 if not namespace_selector and namespace: 213 if not namespace_selector and namespace:
228 ns = self.kubernetes.get( 214 ns = self.kubernetes.get(
229 '{}/namespaces/{}'.format(constants.K8S_API_BASE, namespace)) 215 '{}/namespaces/{}'.format(constants.K8S_API_BASE, namespace))
230 ns_cidr = self._get_namespace_subnet_cidr(ns) 216 ns_cidr = driver_utils.get_namespace_subnet_cidr(ns)
231 cidrs.append(ns_cidr) 217 cidrs.append({'cidr': ns_cidr, 'namespace': namespace})
232 else: 218 else:
233 matching_namespaces = driver_utils.get_namespaces( 219 matching_namespaces = driver_utils.get_namespaces(
234 namespace_selector) 220 namespace_selector)
235 for ns in matching_namespaces.get('items'): 221 for ns in matching_namespaces.get('items'):
236 # NOTE(ltomasbo): This requires the namespace handler to be 222 # NOTE(ltomasbo): This requires the namespace handler to be
237 # also enabled 223 # also enabled
238 ns_cidr = self._get_namespace_subnet_cidr(ns) 224 ns_cidr = driver_utils.get_namespace_subnet_cidr(ns)
239 cidrs.append(ns_cidr) 225 ns_name = ns['metadata']['name']
226 cidrs.append({'cidr': ns_cidr, 'namespace': ns_name})
240 return cidrs 227 return cidrs
241 228
242 def _parse_selectors(self, rule_block, rule_direction, policy_namespace): 229 def _parse_selectors(self, rule_block, rule_direction, policy_namespace):
@@ -315,7 +302,8 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
315 driver_utils.create_security_group_rule_body( 302 driver_utils.create_security_group_rule_body(
316 sg_id, direction, port.get('port'), 303 sg_id, direction, port.get('port'),
317 protocol=port.get('protocol'), 304 protocol=port.get('protocol'),
318 cidr=cidr)) 305 cidr=cidr.get('cidr'),
306 namespace=cidr.get('namespace')))
319 sg_rule_body_list.append(rule) 307 sg_rule_body_list.append(rule)
320 if allow_all: 308 if allow_all:
321 rule = ( 309 rule = (
@@ -334,7 +322,8 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
334 sg_id, direction, 322 sg_id, direction,
335 port_range_min=1, 323 port_range_min=1,
336 port_range_max=65535, 324 port_range_max=65535,
337 cidr=cidr) 325 cidr=cidr.get('cidr'),
326 namespace=cidr.get('namespace'))
338 sg_rule_body_list.append(rule) 327 sg_rule_body_list.append(rule)
339 if allow_all: 328 if allow_all:
340 rule = driver_utils.create_security_group_rule_body( 329 rule = driver_utils.create_security_group_rule_body(
diff --git a/kuryr_kubernetes/controller/drivers/network_policy_security_groups.py b/kuryr_kubernetes/controller/drivers/network_policy_security_groups.py
index 00a3d20..69fda9c 100644
--- a/kuryr_kubernetes/controller/drivers/network_policy_security_groups.py
+++ b/kuryr_kubernetes/controller/drivers/network_policy_security_groups.py
@@ -26,81 +26,6 @@ from oslo_log import log as logging
26LOG = logging.getLogger(__name__) 26LOG = logging.getLogger(__name__)
27 27
28 28
29OPERATORS_WITH_VALUES = [constants.K8S_OPERATOR_IN,
30 constants.K8S_OPERATOR_NOT_IN]
31
32
33def _get_kuryrnetpolicy_crds(namespace=None):
34 kubernetes = clients.get_kubernetes_client()
35
36 try:
37 if namespace:
38 knp_path = '{}/{}/kuryrnetpolicies'.format(
39 constants.K8S_API_CRD_NAMESPACES, namespace)
40 else:
41 knp_path = constants.K8S_API_CRD_KURYRNETPOLICIES
42 LOG.debug("K8s API Query %s", knp_path)
43 knps = kubernetes.get(knp_path)
44 LOG.debug("Return Kuryr Network Policies with label %s", knps)
45 except exceptions.K8sResourceNotFound:
46 LOG.exception("KuryrNetPolicy CRD not found")
47 raise
48 except exceptions.K8sClientException:
49 LOG.exception("Kubernetes Client Exception")
50 raise
51 return knps
52
53
54def _match_expressions(expressions, labels):
55 for exp in expressions:
56 exp_op = exp['operator'].lower()
57 if labels:
58 if exp_op in OPERATORS_WITH_VALUES:
59 exp_values = exp['values']
60 label_value = labels.get(str(exp['key']), None)
61 if exp_op == constants.K8S_OPERATOR_IN:
62 if label_value is None or label_value not in exp_values:
63 return False
64 elif exp_op == constants.K8S_OPERATOR_NOT_IN:
65 if label_value in exp_values:
66 return False
67 else:
68 if exp_op == constants.K8S_OPERATOR_EXISTS:
69 exists = labels.get(str(exp['key']), None)
70 if exists is None:
71 return False
72 elif exp_op == constants.K8S_OPERATOR_DOES_NOT_EXIST:
73 exists = labels.get(str(exp['key']), None)
74 if exists is not None:
75 return False
76 else:
77 if exp_op in (constants.K8S_OPERATOR_IN,
78 constants.K8S_OPERATOR_EXISTS):
79 return False
80 return True
81
82
83def _match_labels(crd_labels, labels):
84 for crd_key, crd_value in crd_labels.items():
85 label_value = labels.get(crd_key, None)
86 if not label_value or crd_value != label_value:
87 return False
88 return True
89
90
91def _match_selector(selector, labels):
92 crd_labels = selector.get('matchLabels', None)
93 crd_expressions = selector.get('matchExpressions', None)
94
95 match_exp = match_lb = True
96 if crd_expressions:
97 match_exp = _match_expressions(crd_expressions,
98 labels)
99 if crd_labels and labels:
100 match_lb = _match_labels(crd_labels, labels)
101 return match_exp and match_lb
102
103
104def _get_namespace_labels(namespace): 29def _get_namespace_labels(namespace):
105 kubernetes = clients.get_kubernetes_client() 30 kubernetes = clients.get_kubernetes_client()
106 31
@@ -119,15 +44,15 @@ def _get_namespace_labels(namespace):
119 return namespaces['metadata'].get('labels') 44 return namespaces['metadata'].get('labels')
120 45
121 46
122def _create_sg_rules(crd, pod, namespace_selector, pod_selector, 47def _create_sg_rules(crd, pod, pod_selector, rule_block, crd_rules,
123 rule_block, crd_rules, direction, 48 direction, matched, namespace=None):
124 matched):
125 pod_labels = pod['metadata'].get('labels') 49 pod_labels = pod['metadata'].get('labels')
126 50
127 # NOTE (maysams) No need to differentiate between podSelector 51 # NOTE (maysams) No need to differentiate between podSelector
128 # with empty value or with '{}', as they have same result in here. 52 # with empty value or with '{}', as they have same result in here.
129 if (pod_selector and 53 if (pod_selector and
130 _match_selector(pod_selector, pod_labels)): 54 driver_utils.match_selector(pod_selector, pod_labels)):
55
131 matched = True 56 matched = True
132 pod_ip = driver_utils.get_pod_ip(pod) 57 pod_ip = driver_utils.get_pod_ip(pod)
133 sg_id = crd['spec']['securityGroupId'] 58 sg_id = crd['spec']['securityGroupId']
@@ -135,7 +60,8 @@ def _create_sg_rules(crd, pod, namespace_selector, pod_selector,
135 for port in rule_block['ports']: 60 for port in rule_block['ports']:
136 sg_rule = driver_utils.create_security_group_rule_body( 61 sg_rule = driver_utils.create_security_group_rule_body(
137 sg_id, direction, port.get('port'), 62 sg_id, direction, port.get('port'),
138 protocol=port.get('protocol'), cidr=pod_ip) 63 protocol=port.get('protocol'), cidr=pod_ip,
64 namespace=namespace)
139 sgr_id = driver_utils.create_security_group_rule(sg_rule) 65 sgr_id = driver_utils.create_security_group_rule(sg_rule)
140 sg_rule['security_group_rule']['id'] = sgr_id 66 sg_rule['security_group_rule']['id'] = sgr_id
141 crd_rules.append(sg_rule) 67 crd_rules.append(sg_rule)
@@ -144,7 +70,8 @@ def _create_sg_rules(crd, pod, namespace_selector, pod_selector,
144 sg_id, direction, 70 sg_id, direction,
145 port_range_min=1, 71 port_range_min=1,
146 port_range_max=65535, 72 port_range_max=65535,
147 cidr=pod_ip) 73 cidr=pod_ip,
74 namespace=namespace)
148 sgr_id = driver_utils.create_security_group_rule(sg_rule) 75 sgr_id = driver_utils.create_security_group_rule(sg_rule)
149 sg_rule['security_group_rule']['id'] = sgr_id 76 sg_rule['security_group_rule']['id'] = sgr_id
150 crd_rules.append(sg_rule) 77 crd_rules.append(sg_rule)
@@ -171,23 +98,22 @@ def _parse_rules(direction, crd, pod):
171 namespace_selector = rule.get('namespaceSelector') 98 namespace_selector = rule.get('namespaceSelector')
172 pod_selector = rule.get('podSelector') 99 pod_selector = rule.get('podSelector')
173 if namespace_selector == {}: 100 if namespace_selector == {}:
174 if _create_sg_rules(crd, pod, namespace_selector, 101 if _create_sg_rules(crd, pod, pod_selector, rule_block,
175 pod_selector, rule_block, crd_rules, 102 crd_rules, direction, matched):
176 direction, matched):
177 matched = True 103 matched = True
178 elif namespace_selector: 104 elif namespace_selector:
179 if (pod_namespace_labels and 105 if (pod_namespace_labels and
180 _match_selector(namespace_selector, 106 driver_utils.match_selector(namespace_selector,
181 pod_namespace_labels)): 107 pod_namespace_labels)):
182 if _create_sg_rules(crd, pod, namespace_selector, 108 if _create_sg_rules(crd, pod, pod_selector, rule_block,
183 pod_selector, rule_block, crd_rules, 109 crd_rules, direction, matched,
184 direction, matched): 110 pod_namespace):
185 matched = True 111 matched = True
186 else: 112 else:
187 if pod_namespace == policy_namespace: 113 if pod_namespace == policy_namespace:
188 if _create_sg_rules(crd, pod, namespace_selector, 114 if _create_sg_rules(crd, pod, pod_selector, rule_block,
189 pod_selector, rule_block, crd_rules, 115 crd_rules, direction, matched,
190 direction, matched): 116 pod_namespace):
191 matched = True 117 matched = True
192 return matched, crd_rules 118 return matched, crd_rules
193 119
@@ -198,11 +124,12 @@ def _get_pod_sgs(pod, project_id):
198 pod_labels = pod['metadata'].get('labels') 124 pod_labels = pod['metadata'].get('labels')
199 pod_namespace = pod['metadata']['namespace'] 125 pod_namespace = pod['metadata']['namespace']
200 126
201 knp_crds = _get_kuryrnetpolicy_crds(namespace=pod_namespace) 127 knp_crds = driver_utils.get_kuryrnetpolicy_crds(
128 namespace=pod_namespace)
202 for crd in knp_crds.get('items'): 129 for crd in knp_crds.get('items'):
203 pod_selector = crd['spec'].get('podSelector') 130 pod_selector = crd['spec'].get('podSelector')
204 if pod_selector: 131 if pod_selector:
205 if _match_selector(pod_selector, pod_labels): 132 if driver_utils.match_selector(pod_selector, pod_labels):
206 LOG.debug("Appending %s", 133 LOG.debug("Appending %s",
207 str(crd['spec']['securityGroupId'])) 134 str(crd['spec']['securityGroupId']))
208 sg_list.append(str(crd['spec']['securityGroupId'])) 135 sg_list.append(str(crd['spec']['securityGroupId']))
@@ -229,7 +156,7 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
229 156
230 def create_sg_rules(self, pod): 157 def create_sg_rules(self, pod):
231 LOG.debug("Creating sg rule for pod: %s", pod['metadata']['name']) 158 LOG.debug("Creating sg rule for pod: %s", pod['metadata']['name'])
232 knp_crds = _get_kuryrnetpolicy_crds() 159 knp_crds = driver_utils.get_kuryrnetpolicy_crds()
233 for crd in knp_crds.get('items'): 160 for crd in knp_crds.get('items'):
234 crd_selector = crd['spec'].get('podSelector') 161 crd_selector = crd['spec'].get('podSelector')
235 162
@@ -244,7 +171,7 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
244 LOG.debug("Deleting sg rule for pod: %s", pod['metadata']['name']) 171 LOG.debug("Deleting sg rule for pod: %s", pod['metadata']['name'])
245 pod_ip = driver_utils.get_pod_ip(pod) 172 pod_ip = driver_utils.get_pod_ip(pod)
246 173
247 knp_crds = _get_kuryrnetpolicy_crds() 174 knp_crds = driver_utils.get_kuryrnetpolicy_crds()
248 for crd in knp_crds.get('items'): 175 for crd in knp_crds.get('items'):
249 crd_selector = crd['spec'].get('podSelector') 176 crd_selector = crd['spec'].get('podSelector')
250 ingress_rule_list = crd['spec'].get('ingressSgRules') 177 ingress_rule_list = crd['spec'].get('ingressSgRules')
@@ -293,6 +220,18 @@ class NetworkPolicySecurityGroupsDriver(base.PodSecurityGroupsDriver):
293 LOG.debug("Security group driver does not implement deleting " 220 LOG.debug("Security group driver does not implement deleting "
294 "SGs.") 221 "SGs.")
295 222
223 def delete_namespace_sg_rules(self, namespace):
224 LOG.debug("Security group driver does not delete SG rules for "
225 "namespace.")
226
227 def create_namespace_sg_rules(self, namespace):
228 LOG.debug("Security group driver does not create SG rules for "
229 "namespace.")
230
231 def update_namespace_sg_rules(self, namespace):
232 LOG.debug("Security group driver does not update SG rules for "
233 "namespace.")
234
296 235
297class NetworkPolicyServiceSecurityGroupsDriver( 236class NetworkPolicyServiceSecurityGroupsDriver(
298 base.ServiceSecurityGroupsDriver): 237 base.ServiceSecurityGroupsDriver):
diff --git a/kuryr_kubernetes/controller/drivers/utils.py b/kuryr_kubernetes/controller/drivers/utils.py
index 6bf8eb0..dc758cd 100644
--- a/kuryr_kubernetes/controller/drivers/utils.py
+++ b/kuryr_kubernetes/controller/drivers/utils.py
@@ -238,7 +238,7 @@ def patch_kuryr_crd(crd, i_rules, e_rules, pod_selector, np_spec=None):
238def create_security_group_rule_body( 238def create_security_group_rule_body(
239 security_group_id, direction, port_range_min, 239 security_group_id, direction, port_range_min,
240 port_range_max=None, protocol=None, ethertype='IPv4', cidr=None, 240 port_range_max=None, protocol=None, ethertype='IPv4', cidr=None,
241 description="Kuryr-Kubernetes NetPolicy SG rule"): 241 description="Kuryr-Kubernetes NetPolicy SG rule", namespace=None):
242 if not port_range_min: 242 if not port_range_min:
243 port_range_min = 1 243 port_range_min = 1
244 port_range_max = 65535 244 port_range_max = 65535
@@ -260,6 +260,8 @@ def create_security_group_rule_body(
260 if cidr: 260 if cidr:
261 security_group_rule_body[u'security_group_rule'][ 261 security_group_rule_body[u'security_group_rule'][
262 u'remote_ip_prefix'] = cidr 262 u'remote_ip_prefix'] = cidr
263 if namespace:
264 security_group_rule_body['namespace'] = namespace
263 LOG.debug("Creating sg rule body %s", security_group_rule_body) 265 LOG.debug("Creating sg rule body %s", security_group_rule_body)
264 return security_group_rule_body 266 return security_group_rule_body
265 267
@@ -280,11 +282,100 @@ def get_pod_ip(pod):
280 return first_subnet_ip 282 return first_subnet_ip
281 283
282 284
283def get_pod_annotated_labels(pod): 285def get_annotated_labels(resource, annotation_labels):
284 try: 286 try:
285 annotations = pod['metadata']['annotations'] 287 annotations = resource['metadata']['annotations']
286 pod_labels_annotation = annotations[constants.K8S_ANNOTATION_LABEL] 288 labels_annotation = annotations[annotation_labels]
287 except KeyError: 289 except KeyError:
288 return None 290 return None
289 pod_labels = jsonutils.loads(pod_labels_annotation) 291 labels = jsonutils.loads(labels_annotation)
290 return pod_labels 292 return labels
293
294
295def get_kuryrnetpolicy_crds(namespace=None):
296 kubernetes = clients.get_kubernetes_client()
297
298 try:
299 if namespace:
300 knp_path = '{}/{}/kuryrnetpolicies'.format(
301 constants.K8S_API_CRD_NAMESPACES, namespace)
302 else:
303 knp_path = constants.K8S_API_CRD_KURYRNETPOLICIES
304 LOG.debug("K8s API Query %s", knp_path)
305 knps = kubernetes.get(knp_path)
306 LOG.debug("Return Kuryr Network Policies with label %s", knps)
307 except k_exc.K8sResourceNotFound:
308 LOG.exception("KuryrNetPolicy CRD not found")
309 raise
310 except k_exc.K8sClientException:
311 LOG.exception("Kubernetes Client Exception")
312 raise
313 return knps
314
315
316def match_expressions(expressions, labels):
317 for exp in expressions:
318 exp_op = exp['operator'].lower()
319 if labels:
320 if exp_op in OPERATORS_WITH_VALUES:
321 exp_values = exp['values']
322 label_value = labels.get(str(exp['key']), None)
323 if exp_op == constants.K8S_OPERATOR_IN:
324 if label_value is None or label_value not in exp_values:
325 return False
326 elif exp_op == constants.K8S_OPERATOR_NOT_IN:
327 if label_value in exp_values:
328 return False
329 else:
330 if exp_op == constants.K8S_OPERATOR_EXISTS:
331 exists = labels.get(str(exp['key']), None)
332 if exists is None:
333 return False
334 elif exp_op == constants.K8S_OPERATOR_DOES_NOT_EXIST:
335 exists = labels.get(str(exp['key']), None)
336 if exists is not None:
337 return False
338 else:
339 if exp_op in (constants.K8S_OPERATOR_IN,
340 constants.K8S_OPERATOR_EXISTS):
341 return False
342 return True
343
344
345def match_labels(crd_labels, labels):
346 for crd_key, crd_value in crd_labels.items():
347 label_value = labels.get(crd_key, None)
348 if not label_value or crd_value != label_value:
349 return False
350 return True
351
352
353def match_selector(selector, labels):
354 crd_labels = selector.get('matchLabels', None)
355 crd_expressions = selector.get('matchExpressions', None)
356
357 match_exp = match_lb = True
358 if crd_expressions:
359 match_exp = match_expressions(crd_expressions,
360 labels)
361 if crd_labels and labels:
362 match_lb = match_labels(crd_labels, labels)
363 return match_exp and match_lb
364
365
366def get_namespace_subnet_cidr(namespace):
367 kubernetes = clients.get_kubernetes_client()
368 try:
369 ns_annotations = namespace['metadata']['annotations']
370 ns_name = ns_annotations[constants.K8S_ANNOTATION_NET_CRD]
371 except KeyError:
372 LOG.exception('Namespace handler must be enabled to support '
373 'Network Policies with namespaceSelector')
374 raise k_exc.ResourceNotReady(namespace)
375 try:
376 net_crd = kubernetes.get('{}/kuryrnets/{}'.format(
377 constants.K8S_API_CRD, ns_name))
378 except k_exc.K8sClientException:
379 LOG.exception("Kubernetes Client Exception.")
380 raise
381 return net_crd['spec']['subnetCIDR']
diff --git a/kuryr_kubernetes/controller/handlers/namespace.py b/kuryr_kubernetes/controller/handlers/namespace.py
index a685dde..d5d82bf 100644
--- a/kuryr_kubernetes/controller/handlers/namespace.py
+++ b/kuryr_kubernetes/controller/handlers/namespace.py
@@ -15,10 +15,12 @@
15from oslo_cache import core as cache 15from oslo_cache import core as cache
16from oslo_config import cfg as oslo_cfg 16from oslo_config import cfg as oslo_cfg
17from oslo_log import log as logging 17from oslo_log import log as logging
18from oslo_serialization import jsonutils
18 19
19from kuryr_kubernetes import clients 20from kuryr_kubernetes import clients
20from kuryr_kubernetes import constants 21from kuryr_kubernetes import constants
21from kuryr_kubernetes.controller.drivers import base as drivers 22from kuryr_kubernetes.controller.drivers import base as drivers
23from kuryr_kubernetes.controller.drivers import utils as drivers_utils
22from kuryr_kubernetes import exceptions 24from kuryr_kubernetes import exceptions
23from kuryr_kubernetes.handlers import k8s_base 25from kuryr_kubernetes.handlers import k8s_base
24from kuryr_kubernetes import utils 26from kuryr_kubernetes import utils
@@ -57,6 +59,17 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
57 self._drv_vif_pool.set_vif_driver() 59 self._drv_vif_pool.set_vif_driver()
58 60
59 def on_present(self, namespace): 61 def on_present(self, namespace):
62 current_namespace_labels = namespace['metadata'].get('labels')
63 previous_namespace_labels = drivers_utils.get_annotated_labels(
64 namespace, constants.K8S_ANNOTATION_NAMESPACE_LABEL)
65 LOG.debug("Got previous namespace labels from annotation: %r",
66 previous_namespace_labels)
67
68 if (previous_namespace_labels and
69 current_namespace_labels != previous_namespace_labels):
70 self._drv_sg.update_namespace_sg_rules(namespace)
71 self._set_namespace_labels(namespace, current_namespace_labels)
72
60 ns_name = namespace['metadata']['name'] 73 ns_name = namespace['metadata']['name']
61 project_id = self._drv_project.get_project(namespace) 74 project_id = self._drv_project.get_project(namespace)
62 net_crd_id = self._get_net_crd_id(namespace) 75 net_crd_id = self._get_net_crd_id(namespace)
@@ -85,6 +98,8 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
85 try: 98 try:
86 net_crd = self._add_kuryrnet_crd(ns_name, net_crd_spec) 99 net_crd = self._add_kuryrnet_crd(ns_name, net_crd_spec)
87 self._set_net_crd(namespace, net_crd) 100 self._set_net_crd(namespace, net_crd)
101 self._drv_sg.create_namespace_sg_rules(namespace)
102 self._set_namespace_labels(namespace, current_namespace_labels)
88 except exceptions.K8sClientException: 103 except exceptions.K8sClientException:
89 LOG.exception("Kuryrnet CRD could not be added. Rolling back " 104 LOG.exception("Kuryrnet CRD could not be added. Rolling back "
90 "network resources created for the namespace.") 105 "network resources created for the namespace.")
@@ -108,8 +123,8 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
108 else: 123 else:
109 LOG.debug("There is no security group associated with the " 124 LOG.debug("There is no security group associated with the "
110 "namespace to be deleted") 125 "namespace to be deleted")
111
112 self._del_kuryrnet_crd(net_crd_id) 126 self._del_kuryrnet_crd(net_crd_id)
127 self._drv_sg.delete_namespace_sg_rules(namespace)
113 128
114 def is_ready(self, quota): 129 def is_ready(self, quota):
115 if not utils.has_kuryr_crd(constants.K8S_API_CRD_KURYRNETS): 130 if not utils.has_kuryr_crd(constants.K8S_API_CRD_KURYRNETS):
@@ -191,3 +206,16 @@ class NamespaceHandler(k8s_base.ResourceEventHandler):
191 LOG.exception("Kubernetes Client Exception deleting kuryrnet " 206 LOG.exception("Kubernetes Client Exception deleting kuryrnet "
192 "CRD.") 207 "CRD.")
193 raise 208 raise
209
210 def _set_namespace_labels(self, namespace, labels):
211 if not labels:
212 LOG.debug("Removing Label annotation: %r", labels)
213 annotation = None
214 else:
215 annotation = jsonutils.dumps(labels, sort_keys=True)
216 LOG.debug("Setting Labels annotation: %r", annotation)
217
218 k8s = clients.get_kubernetes_client()
219 k8s.annotate(namespace['metadata']['selfLink'],
220 {constants.K8S_ANNOTATION_NAMESPACE_LABEL: annotation},
221 resource_version=namespace['metadata']['resourceVersion'])
diff --git a/kuryr_kubernetes/tests/unit/controller/drivers/test_namespace_security_groups.py b/kuryr_kubernetes/tests/unit/controller/drivers/test_namespace_security_groups.py
index 63d452b..3ccf861 100644
--- a/kuryr_kubernetes/tests/unit/controller/drivers/test_namespace_security_groups.py
+++ b/kuryr_kubernetes/tests/unit/controller/drivers/test_namespace_security_groups.py
@@ -61,6 +61,131 @@ def get_namespace_obj():
61 } 61 }
62 62
63 63
64def get_no_match_crd_namespace_obj():
65 return {
66 "kind": "Namespace",
67 "metadata": {
68 "annotations": {
69 "openstack.org/kuryr-namespace-label": '{"name": "dev"}',
70 "openstack.org/kuryr-net-crd": "ns-dev"
71 },
72 "labels": {"name": "prod"},
73 "name": "prod",
74 "selfLink": "/api/v1/namespaces/dev"}}
75
76
77def get_match_crd_namespace_obj():
78 return {
79 "kind": "Namespace",
80 "metadata": {
81 "annotations": {
82 "openstack.org/kuryr-namespace-label": '{"name": "dev"}',
83 "openstack.org/kuryr-net-crd": "ns-dev"
84 },
85 "labels": {
86 "name": "dev"
87 },
88 "name": "dev",
89 "selfLink": "/api/v1/namespaces/dev"}}
90
91
92def get_match_crd_pod_obj():
93 return {
94 'kind': 'Pod',
95 'metadata': {
96 'name': mock.sentinel.pod_name,
97 'namespace': 'dev',
98 'labels': {
99 'tier': 'backend'},
100 'annotations': {
101 'openstack.org/kuryr-pod-label': '{"tier": "backend"}'}},
102 'status': {'podIP': mock.sentinel.podIP}}
103
104
105def get_sg_rule():
106 pod_ip = get_match_crd_pod_obj()['status'].get('podIP')
107 return {
108 "namespace": 'dev',
109 "security_group_rule": {
110 "description": "Kuryr-Kubernetes NetPolicy SG rule",
111 "direction": "ingress",
112 "ethertype": "IPv4",
113 "id": 'f15ff50a-e8a4-4872-81bf-a04cbb8cb388',
114 "port_range_max": 6379,
115 "port_range_min": 6379,
116 "protocol": "tcp",
117 "remote_ip_prefix": pod_ip,
118 "security_group_id": '36923e76-026c-422b-8dfd-7292e7c88228'}}
119
120
121def get_matched_crd_obj():
122 return {
123 "kind": "KuryrNetPolicy",
124 "metadata": {"name": "np-test-network-policy",
125 "namespace": "default"},
126 "spec": {
127 "egressSgRules": [],
128 "ingressSgRules": [get_sg_rule()],
129 "networkpolicy_spec": {
130 "ingress": [
131 {"from": [
132 {"namespaceSelector": {
133 "matchLabels": {"name": "dev"}}}],
134 "ports": [
135 {"port": 6379,
136 "protocol": "TCP"}]}],
137 "podSelector": {"matchLabels": {"app": "demo"}},
138 "policyTypes": ["Ingress"]},
139 "podSelector": {"matchLabels": {"app": "demo"}},
140 "securityGroupId": '36923e76-026c-422b-8dfd-7292e7c88228'}}
141
142
143def get_crd_obj_no_match():
144 return {
145 "kind": "KuryrNetPolicy",
146 "metadata": {"name": "np-test-network-policy",
147 "namespace": "default"},
148 "spec": {
149 "egressSgRules": [],
150 "ingressSgRules": [],
151 "networkpolicy_spec": {
152 "ingress": [
153 {"from": [
154 {"namespaceSelector": {
155 "matchLabels": {"name": "dev"}}}],
156 "ports": [
157 {"port": 6379,
158 "protocol": "TCP"}]}],
159 "podSelector": {"matchLabels": {"app": "demo"}},
160 "policyTypes": ["Ingress"]},
161 "podSelector": {"matchLabels": {"app": "demo"}},
162 "securityGroupId": '36923e76-026c-422b-8dfd-7292e7c88228'}}
163
164
165def get_crd_obj_with_all_selectors():
166 return {
167 "kind": "KuryrNetPolicy",
168 "metadata": {"name": "np-test-network-policy",
169 "namespace": "default"},
170 "spec": {
171 "egressSgRules": [],
172 "ingressSgRules": [],
173 "networkpolicy_spec": {
174 "ingress": [
175 {"from": [
176 {"namespaceSelector": {
177 "matchLabels": {"name": "dev"}},
178 "podSelector": {
179 "matchLabels": {"tier": "backend"}}}],
180 "ports": [
181 {"port": 6379,
182 "protocol": "TCP"}]}],
183 "podSelector": {"matchLabels": {"app": "demo"}},
184 "policyTypes": ["Ingress"]},
185 "podSelector": {"matchLabels": {"app": "demo"}},
186 "securityGroupId": '36923e76-026c-422b-8dfd-7292e7c88228'}}
187
188
64class TestNamespacePodSecurityGroupsDriver(test_base.TestCase): 189class TestNamespacePodSecurityGroupsDriver(test_base.TestCase):
65 190
66 @mock.patch('kuryr_kubernetes.controller.drivers.' 191 @mock.patch('kuryr_kubernetes.controller.drivers.'
@@ -165,3 +290,143 @@ class TestNamespacePodSecurityGroupsDriver(test_base.TestCase):
165 290
166 cls.delete_sg(m_driver, sg_id) 291 cls.delete_sg(m_driver, sg_id)
167 neutron.delete_security_group.assert_called_once_with(sg_id) 292 neutron.delete_security_group.assert_called_once_with(sg_id)
293
294 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
295 'patch_kuryr_crd')
296 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
297 'delete_security_group_rule')
298 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
299 'get_kuryrnetpolicy_crds')
300 def test_delete_namespace_sg_rule(self, m_get_knp_crd, m_delete_sg_rule,
301 m_patch_kuryr_crd):
302 cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
303 m_driver = mock.MagicMock(spec=cls)
304 i_rule = get_matched_crd_obj()['spec']['ingressSgRules'][0]
305 sg_rule_id = i_rule.get('security_group_rule')['id']
306
307 m_get_knp_crd.return_value = {"items": [get_matched_crd_obj()]}
308
309 cls.delete_namespace_sg_rules(m_driver, get_match_crd_namespace_obj())
310
311 m_get_knp_crd.assert_called_once()
312 m_delete_sg_rule.assert_called_once_with(sg_rule_id)
313 m_patch_kuryr_crd.assert_called_once()
314
315 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
316 'patch_kuryr_crd')
317 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
318 'delete_security_group_rule')
319 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
320 'get_kuryrnetpolicy_crds')
321 def test_delete_namespace_sg_rule_no_match(self, m_get_knp_crd,
322 m_delete_sg_rule,
323 m_patch_kuryr_crd):
324 cls = namespace_security_groups.NamespacePodSecurityGroupsDriver
325 m_driver = mock.MagicMock(spec=cls)
326
327 m_get_knp_crd.return_value = {"items": [get_matched_crd_obj()]}
328
329 cls.delete_namespace_sg_rules(m_driver,
330 get_no_match_crd_namespace_obj())
331
332 m_get_knp_crd.assert_called_once()
333 m_delete_sg_rule.assert_not_called()
334 m_patch_kuryr_crd.assert_not_called()
335
336 @mock.patch('kuryr_kubernetes.controller.drivers.'
337 'namespace_security_groups._create_sg_rule')
338 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
339 'match_selector')
340 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
341 'get_namespace_subnet_cidr')
342 def test__parse_rules(self, m_get_ns_subnet_cidr, m_match_selector,
343 m_create_sg_rule):
344 crd = get_crd_obj_no_match()
345 policy = crd['spec']['networkpolicy_spec']
346 i_rule = policy.get('ingress')[0]
347 ns_selector = i_rule['from'][0].get('namespaceSelector')
348 ns = get_match_crd_namespace_obj()
349
350 m_get_ns_subnet_cidr.return_value = '10.0.2.0/26'
351 m_match_selector.return_value = True
352 m_create_sg_rule.return_value = get_sg_rule()
353
354 matched, rules = namespace_security_groups._parse_rules('ingress',
355 crd, ns)
356
357 m_get_ns_subnet_cidr.assert_called_once_with(ns)
358 m_match_selector.assert_called_once_with(ns_selector,
359 ns['metadata']['labels'])
360 m_create_sg_rule.assert_called_once()
361
362 self.assertEqual(matched, True)
363 self.assertEqual(rules, [get_sg_rule()])
364
365 @mock.patch('kuryr_kubernetes.controller.drivers.'
366 'namespace_security_groups._create_sg_rule')
367 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
368 'match_selector')
369 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
370 'get_namespace_subnet_cidr')
371 def test__parse_rules_no_match(self, m_get_ns_subnet_cidr,
372 m_match_selector, m_create_sg_rule):
373 crd = get_crd_obj_no_match()
374 policy = crd['spec']['networkpolicy_spec']
375 i_rule = policy.get('ingress')[0]
376 ns_selector = i_rule['from'][0].get('namespaceSelector')
377 ns = get_no_match_crd_namespace_obj()
378
379 m_get_ns_subnet_cidr.return_value = '10.0.2.0/26'
380 m_match_selector.return_value = False
381
382 matched, rules = namespace_security_groups._parse_rules('ingress',
383 crd, ns)
384
385 m_get_ns_subnet_cidr.assert_called_once_with(ns)
386 m_match_selector.assert_called_once_with(ns_selector,
387 ns['metadata']['labels'])
388 m_create_sg_rule.assert_not_called()
389
390 self.assertEqual(matched, False)
391 self.assertEqual(rules, [])
392
393 @mock.patch('kuryr_kubernetes.controller.drivers.'
394 'namespace_security_groups._create_sg_rule')
395 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
396 'get_pod_ip')
397 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
398 'get_pods')
399 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
400 'match_selector')
401 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
402 'get_namespace_subnet_cidr')
403 def test__parse_rules_all_selectors(self, m_get_ns_subnet_cidr,
404 m_match_selector, m_get_pods,
405 m_get_pod_ip, m_create_sg_rule):
406 crd = get_crd_obj_with_all_selectors()
407 policy = crd['spec']['networkpolicy_spec']
408 i_rule = policy.get('ingress')[0]
409 ns_selector = i_rule['from'][0].get('namespaceSelector')
410 pod_selector = i_rule['from'][0].get('podSelector')
411 ns = get_match_crd_namespace_obj()
412 pod = get_match_crd_pod_obj()
413
414 m_get_ns_subnet_cidr.return_value = '10.0.2.0/26'
415 m_match_selector.return_value = True
416 m_get_pods.return_value = {"items": [pod]}
417 m_get_pod_ip.return_value = pod['status']['podIP']
418 m_create_sg_rule.return_value = get_sg_rule()
419
420 matched, rules = namespace_security_groups._parse_rules('ingress',
421 crd, ns)
422
423 m_get_ns_subnet_cidr.assert_called_once_with(ns)
424 m_match_selector.assert_called_once_with(ns_selector,
425 ns['metadata']['labels'])
426 m_get_pods.assert_called_once_with(pod_selector,
427 ns['metadata']['name'])
428 m_get_pod_ip.assert_called_once_with(pod)
429 m_create_sg_rule.assert_called_once()
430
431 self.assertEqual(matched, True)
432 self.assertEqual(rules, [get_sg_rule()])
diff --git a/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy.py b/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy.py
index 8924419..ff57dae 100644
--- a/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy.py
+++ b/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy.py
@@ -302,7 +302,7 @@ class TestNetworkPolicyDriver(test_base.TestCase):
302 self.kubernetes.get.side_effect = [{'items': [pod]}, net_crd] 302 self.kubernetes.get.side_effect = [{'items': [pod]}, net_crd]
303 303
304 resp = self._driver._get_namespaces_cidr(namespace_selector) 304 resp = self._driver._get_namespaces_cidr(namespace_selector)
305 self.assertEqual([subnet_cidr], resp) 305 self.assertEqual(subnet_cidr, resp[0].get('cidr'))
306 self.kubernetes.get.assert_called() 306 self.kubernetes.get.assert_called()
307 307
308 def test_get_namespaces_cidr_no_matches(self): 308 def test_get_namespaces_cidr_no_matches(self):
@@ -330,7 +330,7 @@ class TestNetworkPolicyDriver(test_base.TestCase):
330 def test_parse_network_policy_rules_with_rules(self, m_create, 330 def test_parse_network_policy_rules_with_rules(self, m_create,
331 m_get_ns_cidr): 331 m_get_ns_cidr):
332 subnet_cidr = '10.10.0.0/24' 332 subnet_cidr = '10.10.0.0/24'
333 m_get_ns_cidr.return_value = [subnet_cidr] 333 m_get_ns_cidr.return_value = [{'cidr': subnet_cidr, 'namespace': ''}]
334 self._driver.parse_network_policy_rules(self._policy, self._sg_id) 334 self._driver.parse_network_policy_rules(self._policy, self._sg_id)
335 m_create.assert_called() 335 m_create.assert_called()
336 m_get_ns_cidr.assert_called() 336 m_get_ns_cidr.assert_called()
@@ -374,7 +374,7 @@ class TestNetworkPolicyDriver(test_base.TestCase):
374 def test_parse_network_policy_rules_with_no_ports(self, m_create, 374 def test_parse_network_policy_rules_with_no_ports(self, m_create,
375 m_get_ns_cidr): 375 m_get_ns_cidr):
376 subnet_cidr = '10.10.0.0/24' 376 subnet_cidr = '10.10.0.0/24'
377 m_get_ns_cidr.return_value = [subnet_cidr] 377 m_get_ns_cidr.return_value = [{'cidr': subnet_cidr, 'namespace': ''}]
378 policy = self._policy.copy() 378 policy = self._policy.copy()
379 selectors = {'namespaceSelector': { 379 selectors = {'namespaceSelector': {
380 'matchLabels': { 380 'matchLabels': {
@@ -389,9 +389,11 @@ class TestNetworkPolicyDriver(test_base.TestCase):
389 self._driver.parse_network_policy_rules(policy, self._sg_id) 389 self._driver.parse_network_policy_rules(policy, self._sg_id)
390 m_get_ns_cidr.assert_called() 390 m_get_ns_cidr.assert_called()
391 calls = [mock.call(self._sg_id, 'ingress', port_range_min=1, 391 calls = [mock.call(self._sg_id, 'ingress', port_range_min=1,
392 port_range_max=65535, cidr=subnet_cidr), 392 port_range_max=65535, cidr=subnet_cidr,
393 namespace=''),
393 mock.call(self._sg_id, 'egress', port_range_min=1, 394 mock.call(self._sg_id, 'egress', port_range_min=1,
394 port_range_max=65535, cidr=subnet_cidr)] 395 port_range_max=65535, cidr=subnet_cidr,
396 namespace='')]
395 m_create.assert_has_calls(calls) 397 m_create.assert_has_calls(calls)
396 398
397 def test_knps_on_namespace(self): 399 def test_knps_on_namespace(self):
diff --git a/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy_security_groups.py b/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy_security_groups.py
index 3ca030c..69de89e 100644
--- a/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy_security_groups.py
+++ b/kuryr_kubernetes/tests/unit/controller/drivers/test_network_policy_security_groups.py
@@ -258,8 +258,8 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
258 'create_security_group_rule') 258 'create_security_group_rule')
259 @mock.patch('kuryr_kubernetes.controller.drivers.utils.' 259 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
260 'create_security_group_rule_body') 260 'create_security_group_rule_body')
261 @mock.patch.object(network_policy_security_groups, 261 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
262 '_match_selector', return_value=True) 262 'match_selector', return_value=True)
263 @mock.patch('kuryr_kubernetes.controller.drivers.utils.get_pod_ip') 263 @mock.patch('kuryr_kubernetes.controller.drivers.utils.get_pod_ip')
264 def test__create_sg_rules(self, m_get_pod_ip, 264 def test__create_sg_rules(self, m_get_pod_ip,
265 m_match_selector, 265 m_match_selector,
@@ -277,16 +277,15 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
277 policy = crd['spec']['networkpolicy_spec'] 277 policy = crd['spec']['networkpolicy_spec']
278 rule_list = policy.get('ingress', None) 278 rule_list = policy.get('ingress', None)
279 crd_rules = crd['spec'].get('ingressSgRules') 279 crd_rules = crd['spec'].get('ingressSgRules')
280 pod_ns = pod['metadata']['namespace']
280 281
281 for rule_block in rule_list: 282 for rule_block in rule_list:
282 for rule in rule_block.get('from', []): 283 for rule in rule_block.get('from', []):
283 namespace_selector = rule.get('namespaceSelector')
284 pod_selector = rule.get('podSelector') 284 pod_selector = rule.get('podSelector')
285 matched = network_policy_security_groups._create_sg_rules( 285 matched = network_policy_security_groups._create_sg_rules(
286 crd, pod, namespace_selector, pod_selector, rule_block, 286 crd, pod, pod_selector, rule_block,
287 crd_rules, 'ingress', matched) 287 crd_rules, 'ingress', matched, pod_ns)
288 new_sg_rule['namespaceSelector'] = namespace_selector 288 new_sg_rule['namespace'] = pod_ns
289 new_sg_rule['podSelector'] = pod_selector
290 new_sg_rule['security_group_rule']['id'] = sgr_id 289 new_sg_rule['security_group_rule']['id'] = sgr_id
291 m_match_selector.assert_called_once_with( 290 m_match_selector.assert_called_once_with(
292 pod_selector, pod['metadata']['labels']) 291 pod_selector, pod['metadata']['labels'])
@@ -296,8 +295,8 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
296 self.assertEqual([new_sg_rule], crd_rules) 295 self.assertEqual([new_sg_rule], crd_rules)
297 self.assertEqual(matched, True) 296 self.assertEqual(matched, True)
298 297
299 @mock.patch.object(network_policy_security_groups, 298 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
300 '_match_selector', return_value=False) 299 'match_selector', return_value=False)
301 def test__create_sg_rules_no_match(self, m_match_selector): 300 def test__create_sg_rules_no_match(self, m_match_selector):
302 crd = self._crd_without_rules 301 crd = self._crd_without_rules
303 pod = self._pod2 302 pod = self._pod2
@@ -308,17 +307,16 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
308 307
309 for rule_block in rule_list: 308 for rule_block in rule_list:
310 for rule in rule_block.get('from', []): 309 for rule in rule_block.get('from', []):
311 namespace_selector = rule.get('namespaceSelector')
312 pod_selector = rule.get('podSelector') 310 pod_selector = rule.get('podSelector')
313 matched = network_policy_security_groups._create_sg_rules( 311 matched = network_policy_security_groups._create_sg_rules(
314 crd, pod, namespace_selector, pod_selector, rule_block, 312 crd, pod, pod_selector, rule_block,
315 crd_rules, 'ingress', False) 313 crd_rules, 'ingress', False, self._namespace)
316 self.assertEqual(matched, False) 314 self.assertEqual(matched, False)
317 315
318 @mock.patch('kuryr_kubernetes.controller.drivers.utils.' 316 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
319 'patch_kuryr_crd') 317 'patch_kuryr_crd')
320 @mock.patch.object(network_policy_security_groups, 318 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
321 '_get_kuryrnetpolicy_crds') 319 'get_kuryrnetpolicy_crds')
322 @mock.patch('kuryr_kubernetes.controller.drivers.utils.' 320 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
323 'delete_security_group_rule') 321 'delete_security_group_rule')
324 @mock.patch('kuryr_kubernetes.controller.drivers.utils.get_pod_ip') 322 @mock.patch('kuryr_kubernetes.controller.drivers.utils.get_pod_ip')
@@ -347,8 +345,8 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
347 crd, i_rules, e_rules, crd['spec'].get('podSelector')) 345 crd, i_rules, e_rules, crd['spec'].get('podSelector'))
348 346
349 @mock.patch('kuryr_kubernetes.config.CONF') 347 @mock.patch('kuryr_kubernetes.config.CONF')
350 @mock.patch.object(network_policy_security_groups, 348 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
351 '_get_kuryrnetpolicy_crds') 349 'get_kuryrnetpolicy_crds')
352 def test_get_sgs_for_pod_without_label(self, m_get_crds, m_cfg): 350 def test_get_sgs_for_pod_without_label(self, m_get_crds, m_cfg):
353 m_get_crds.return_value = self._crds 351 m_get_crds.return_value = self._crds
354 sg_list = [str(mock.sentinel.sg_id)] 352 sg_list = [str(mock.sentinel.sg_id)]
@@ -360,12 +358,12 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
360 m_get_crds.assert_called_once_with(namespace=self._namespace) 358 m_get_crds.assert_called_once_with(namespace=self._namespace)
361 self.assertEqual(sg_list, sgs) 359 self.assertEqual(sg_list, sgs)
362 360
363 @mock.patch.object(network_policy_security_groups, 361 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
364 '_match_expressions') 362 'match_expressions')
365 @mock.patch.object(network_policy_security_groups, 363 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
366 '_match_labels') 364 'match_labels')
367 @mock.patch.object(network_policy_security_groups, 365 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
368 '_get_kuryrnetpolicy_crds') 366 'get_kuryrnetpolicy_crds')
369 def test_get_sgs_for_pod_with_label(self, m_get_crds, m_match_labels, 367 def test_get_sgs_for_pod_with_label(self, m_get_crds, m_match_labels,
370 m_match_expressions): 368 m_match_expressions):
371 m_get_crds.return_value = self._crds 369 m_get_crds.return_value = self._crds
@@ -382,12 +380,12 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
382 self.assertEqual(resp, [str(self._sg_id)]) 380 self.assertEqual(resp, [str(self._sg_id)])
383 381
384 @mock.patch('kuryr_kubernetes.config.CONF') 382 @mock.patch('kuryr_kubernetes.config.CONF')
385 @mock.patch.object(network_policy_security_groups, 383 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
386 '_match_expressions') 384 'match_expressions')
387 @mock.patch.object(network_policy_security_groups, 385 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
388 '_match_labels') 386 'match_labels')
389 @mock.patch.object(network_policy_security_groups, 387 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
390 '_get_kuryrnetpolicy_crds') 388 'get_kuryrnetpolicy_crds')
391 def test_get_sgs_for_pod_with_label_no_match(self, m_get_crds, 389 def test_get_sgs_for_pod_with_label_no_match(self, m_get_crds,
392 m_match_labels, 390 m_match_labels,
393 m_match_expressions, m_cfg): 391 m_match_expressions, m_cfg):
@@ -407,8 +405,8 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
407 self._crd['spec']['podSelector']['matchLabels'], pod_labels) 405 self._crd['spec']['podSelector']['matchLabels'], pod_labels)
408 self.assertEqual(sg_list, sgs) 406 self.assertEqual(sg_list, sgs)
409 407
410 @mock.patch.object(network_policy_security_groups, 408 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
411 '_get_kuryrnetpolicy_crds') 409 'get_kuryrnetpolicy_crds')
412 def test_get_sgs_no_crds(self, m_get_crds): 410 def test_get_sgs_no_crds(self, m_get_crds):
413 m_get_crds.return_value = self._empty_crds 411 m_get_crds.return_value = self._empty_crds
414 cfg.CONF.set_override('pod_security_groups', [], 412 cfg.CONF.set_override('pod_security_groups', [],
@@ -419,12 +417,12 @@ class TestNetworkPolicySecurityGroupsDriver(test_base.TestCase):
419 self._project_id) 417 self._project_id)
420 m_get_crds.assert_called_with(namespace=self._namespace) 418 m_get_crds.assert_called_with(namespace=self._namespace)
421 419
422 @mock.patch.object(network_policy_security_groups, 420 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
423 '_match_expressions') 421 'match_expressions')
424 @mock.patch.object(network_policy_security_groups, 422 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
425 '_match_labels') 423 'match_labels')
426 @mock.patch.object(network_policy_security_groups, 424 @mock.patch('kuryr_kubernetes.controller.drivers.utils.'
427 '_get_kuryrnetpolicy_crds') 425 'get_kuryrnetpolicy_crds')
428 def test_get_sgs_multiple_crds(self, m_get_crds, m_match_labels, 426 def test_get_sgs_multiple_crds(self, m_get_crds, m_match_labels,
429 m_match_expressions): 427 m_match_expressions):
430 m_match_expressions.return_value = True 428 m_match_expressions.return_value = True