Skip to content

Commit

Permalink
Merge "Network policy multi-label support"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and opencontrail-ci-admin committed Feb 16, 2017
2 parents b9a97cd + 3c7f5e5 commit f7532f7
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 103 deletions.
34 changes: 34 additions & 0 deletions src/container/kube-manager/kube_manager/vnc/config_db.py
Expand Up @@ -482,6 +482,10 @@ def __init__(self, uuid, obj_dict=None):
self.virtual_machine_interfaces = set()
self.annotations = None
self.rule_entries = None
self.src_ns_selector = None
self.src_pod_selector = None
self.dst_pod_selector = None
self.dst_ports = None
obj_dict = self.update(obj_dict)
super(SecurityGroupKM, self).__init__(uuid, obj_dict)

Expand All @@ -492,9 +496,39 @@ def update(self, obj=None):
self.fq_name = obj['fq_name']
self.update_multiple_refs('virtual_machine_interface', obj)
self.annotations = obj.get('annotations', None)
self._set_selectors(self.annotations)
self.rule_entries = obj.get('security_group_entries', None)
return obj

def _set_selectors(self, annotations):
if not annotations:
return
for kvp in annotations.get('key_value_pair', []):
if kvp.get('key') == 'spec':
break
specjson = json.loads(kvp.get('value'))

pod_selector = specjson.get('podSelector')
if pod_selector:
self.dst_pod_selector = pod_selector.get('matchLabels')

ingress = specjson.get('ingress')
if not ingress:
return
for rule in ingress:
self.dst_ports = rule.get('ports')
from_rule = rule.get('from')
if not from_rule:
continue
for item in from_rule or []:
ns_selector = item.get('namespaceSelector')
if ns_selector:
self.src_ns_selector = ns_selector.get('matchLabels')
continue
pod_selector = item.get('podSelector')
if pod_selector:
self.src_pod_selector = pod_selector.get('matchLabels')

@classmethod
def delete(cls, uuid):
if uuid not in cls._dict:
Expand Down
2 changes: 0 additions & 2 deletions src/container/kube-manager/kube_manager/vnc/label_cache.py
Expand Up @@ -25,5 +25,3 @@ def _remove_label(self, key, cache, label, uuid):
cache[key].remove(uuid)
except KeyError:
pass

cache[key] = set()
146 changes: 52 additions & 94 deletions src/container/kube-manager/kube_manager/vnc/vnc_network_policy.py
Expand Up @@ -22,14 +22,20 @@ def __init__(self, vnc_lib=None, label_cache=None, logger=None):
self.policy_src_label_cache = {}
self.policy_dest_label_cache = {}

def _select_pods(self, labels):
def _select_pods(self, labels, pod_set=None):
result = set()
for label in labels.items():
key = self._label_cache._get_key(label)
pod_ids = self._label_cache.pod_label_cache.get(key)
if not pod_ids:
continue
result.update(pod_ids)
if not result:
result = pod_ids.copy()
else:
result.intersection_update(pod_ids)

if pod_set:
result.intersection_update(pod_set)
return result

def _add_sg_rule(self, sg, sg_rule):
Expand Down Expand Up @@ -65,73 +71,39 @@ def _delete_sg_rule(self, sg_uuid, rule_uuid):
sg_obj.set_security_group_entries(rules)
self._vnc_lib.security_group_update(sg_obj)

def _get_src_labels_from_annotations(self, annotations):
if not annotations:
return
for kvp in annotations.get('key_value_pair', []):
if kvp.get('key') != 'spec':
def _add_src_pod_2_policy(self, pod_id, policy_list):
for policy_id in policy_list:
sg = SecurityGroupKM.get(policy_id)
if not sg:
continue
specjson = json.loads(kvp.get('value'))
return specjson['ingress']
if self._select_pods(sg.src_pod_selector, {pod_id}):
self._set_sg_rule(sg, pod_id)

def _get_dst_labels_from_annotations(self, annotations):
if not annotations:
return
for kvp in annotations.get('key_value_pair', []):
if kvp.get('key') != 'spec':
def _add_dst_pod_2_policy(self, pod_id, policy_list):
for policy_id in policy_list:
sg = SecurityGroupKM.get(policy_id)
if not sg:
continue
specjson = json.loads(kvp.get('value'))
return specjson['podSelector']['matchLabels']

def _add_src_pod_2_policy(self, pod_id, policy_id):
sg = SecurityGroupKM.get(policy_id)
if not sg:
return

rules = self._get_src_labels_from_annotations(sg.annotations)
for rule in rules:
ports = rule.get('ports')
self._set_sg_rule(sg, pod_id, ports)
if self._select_pods(sg.dst_pod_selector, {pod_id}):
self._sg_2_pod_link(pod_id, policy_id, 'ADD')

def vnc_pod_add(self, event):
labels = event['object']['metadata'].get('labels', {})
labels = event['object']['metadata']['labels']
pod_id = event['object']['metadata']['uid']

policy_src_list = set()
policy_dst_list = set()
for label in labels.items():
key = self._label_cache._get_key(label)

policy_ids = self.policy_src_label_cache.get(key, [])
for policy_id in policy_ids:
self._add_src_pod_2_policy(pod_id, policy_id)
policy_src_list.update(policy_ids)

policy_ids = self.policy_dest_label_cache.get(key, [])
for policy_id in policy_ids:
self._sg_2_pod_link(pod_id, policy_id, 'ADD')
policy_dst_list.update(policy_ids)

def _get_label_diff(self, old_labels, new_labels):
if old_labels == new_labels:
return None

diff = dict()
added = {}
removed = {}
changed = {}
keys = set(old_labels.keys()) | set(new_labels.keys())
for k in keys:
if k not in old_labels.keys():
added[k] = new_labels[k]
continue
if k not in new_labels.keys():
removed[k] = old_labels[k]
continue
if old_labels[k] == new_labels[k]:
continue
changed[k] = old_labels[k]

diff['added'] = added
diff['removed'] = removed
diff['changed'] = changed
return diff
self._add_src_pod_2_policy(pod_id, policy_src_list)
self._add_dst_pod_2_policy(pod_id, policy_dst_list)

def _check_deleted_labels(self, deleted_labels, vm):
if not deleted_labels:
Expand All @@ -146,9 +118,9 @@ def _check_deleted_labels(self, deleted_labels, vm):
# check if pod link to be deleted
for sg_id in vmi.security_groups:
sg = SecurityGroupKM.get(sg_id)
if not sg:
if not sg or not sg.dst_pod_selector:
continue
dst_labels = self._get_dst_labels_from_annotations(sg.annotations)
dst_labels = sg.dst_pod_selector
if set(deleted_labels.keys()).intersection(set(dst_labels.keys())):
self._sg_2_pod_link(vm.uuid, sg_id, 'DELETE')

Expand All @@ -173,9 +145,9 @@ def _check_changed_labels(self, changed_labels, vm):
# check if pod link to be deleted
for sg_id in vmi.security_groups:
sg = SecurityGroupKM.get(sg_id)
if not sg:
if not sg or not sg.dst_pod_selector:
continue
dst_labels = self._get_dst_labels_from_annotations(sg.annotations)
dst_labels = sg.dst_pod_selector
if set(changed_labels.keys()).intersection(set(dst_labels.keys())):
self._sg_2_pod_link(vm.uuid, sg_id, 'DELETE')

Expand All @@ -187,22 +159,22 @@ def _check_changed_labels(self, changed_labels, vm):
for policy_id in policy_ids:
self._delete_sg_rule(policy_id, vm.uuid)

def vnc_pod_update(self, event):
def vnc_pod_update(self, event, label_diff):
if not label_diff:
return

labels = event['object']['metadata']['labels']
pod_id = event['object']['metadata']['uid']
vm = VirtualMachineKM.get(pod_id)
if not vm:
return
diff = self._get_label_diff(vm.pod_labels, labels)
if not diff:
return

self._check_deleted_labels(diff['removed'], vm)
self._check_changed_labels(diff['changed'], vm)
self._check_deleted_labels(label_diff['removed'], vm)
self._check_changed_labels(label_diff['changed'], vm)
self.vnc_pod_add(event)

def vnc_pod_delete(self, event):
labels = event['object']['metadata'].get('labels', {})
labels = event['object']['metadata']['labels']
pod_id = event['object']['metadata']['uid']

for label in labels.items():
Expand All @@ -212,7 +184,7 @@ def vnc_pod_delete(self, event):
for policy_id in policy_ids:
self._delete_sg_rule(policy_id, pod_id)

def _set_sg_rule(self, sg, src_pod, ports):
def _set_sg_rule(self, sg, src_pod):
vm = VirtualMachineKM.get(src_pod)
if not vm:
return
Expand All @@ -233,7 +205,7 @@ def _set_sg_rule(self, sg, src_pod, ports):
sgr_uuid = src_pod
src_addr = AddressType(subnet=SubnetType(ip_addr, 32))
dst_addr = AddressType(security_group='local')
for port in ports:
for port in sg.dst_ports:
proto = port['protocol'].lower()
rule = PolicyRuleType(rule_uuid=sgr_uuid, direction='>',
protocol=proto,
Expand All @@ -245,24 +217,15 @@ def _set_sg_rule(self, sg, src_pod, ports):
self._add_sg_rule(sg, rule)

def _set_sg_rules(self, sg, event):
update = False
rules = event['object']['spec']['ingress']
for rule in rules:
ports = rule['ports']
src_selectors = rule['from']
for src_selector in src_selectors:
podSelector = src_selector.get('podSelector', None)
if not podSelector:
continue

src_labels = podSelector['matchLabels']
for src_label in src_labels.items():
key = self._label_cache._get_key(src_label)
self._label_cache._locate_label(key,
self.policy_src_label_cache, src_label, sg.uuid)
src_pods = self._select_pods(src_labels)
for src_pod in src_pods:
self._set_sg_rule(sg, src_pod, ports)
if not sg.src_pod_selector:
return
for src_label in sg.src_pod_selector.items():
key = self._label_cache._get_key(src_label)
self._label_cache._locate_label(key,
self.policy_src_label_cache, src_label, sg.uuid)
src_pods = self._select_pods(sg.src_pod_selector)
for src_pod in src_pods:
self._set_sg_rule(sg, src_pod)

def _sg_2_pod_link(self, pod_id, sg_id, oper):
vm = VirtualMachineKM.get(pod_id)
Expand Down Expand Up @@ -298,21 +261,16 @@ def _sg_2_pod_link(self, pod_id, sg_id, oper):
(default_oper, pod_id, sg_uuid))

def _apply_sg_2_pods(self, sg, event):
podSelector = event['object']['spec'].get('podSelector', None)
if not podSelector:
return

dest_labels = podSelector['matchLabels']
if not dest_labels:
if not sg.dst_pod_selector:
return

uuid = event['object']['metadata'].get('uid')
for dest_label in dest_labels.items():
for dest_label in sg.dst_pod_selector.items():
key = self._label_cache._get_key(dest_label)
self._label_cache._locate_label(key, self.policy_dest_label_cache,
dest_label, uuid)

pod_ids = self._select_pods(dest_labels)
pod_ids = self._select_pods(sg.dst_pod_selector)
for pod_id in pod_ids:
self._sg_2_pod_link(pod_id, sg.uuid, 'ADD')

Expand Down

0 comments on commit f7532f7

Please sign in to comment.