def _add_pod_to_service(self, service_id, pod_id, port=None): lb = LoadbalancerKM.get(service_id) if not lb: return vm = VirtualMachineKM.get(pod_id) if not vm: return for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for vmi_id in vm.virtual_machine_interfaces: vmi = VirtualMachineInterfaceKM.get(vmi_id) if not vmi: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member and member.vmi == vmi_id: break else: self.logger.debug( "Creating LB member for Pod/VM: %s in LB: %s with " "target-port: %d" % (vm.fq_name, lb.name, port['port'])) member_obj = self._vnc_create_member( pool, pod_id, vmi_id, port['port']) LoadbalancerMemberKM.locate(member_obj.uuid)
def vnc_service_add(self, service_id, service_name, service_namespace, service_ip, selectors, ports, service_type, externalIps, loadBalancerIp, specified_fip_pool_fq_name_str): ingress_update = False lb = LoadbalancerKM.get(service_id) if not lb: ingress_update = True self._check_service_uuid_change(service_id, service_name, service_namespace, ports) self._lb_create(service_id, service_name, service_namespace, service_ip, ports) # "kubernetes" service needs a link-local service to be created. # This link-local service will steer traffic destined for # "kubernetes" service from slave (compute) nodes to kube-api server # running on master (control) node. if service_name == self._kubernetes_service_name: self._create_link_local_service(service_name, service_namespace, service_ip, ports) self._update_service_public_ip(service_id, service_name, service_namespace, service_type, externalIps, loadBalancerIp, specified_fip_pool_fq_name_str) if ingress_update: self._ingress_mgr.update_ingress_backend(service_namespace, service_name, 'ADD')
def _get_pods_attached_to_service(self, service_id, port=None): """ Get list of Pods attached to the Service for a given port. """ pod_members = set() lb = LoadbalancerKM.get(service_id) if not lb: return pod_members # No listeners on LB. Error condition. Handle gracefully.. if len(lb.loadbalancer_listeners) == 0: self.logger.warning("No listeners on LB ({})".format(lb.name)) return pod_members for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member.vm: pod_members.add(member.vm) return pod_members
def _sync_service_lb(self): lb_uuid_set = set(LoadbalancerKM.keys()) service_uuid_set = set(ServiceKM.keys()) deleted_uuid_set = lb_uuid_set - service_uuid_set for uuid in deleted_uuid_set: lb = LoadbalancerKM.get(uuid) if not lb: continue if not lb.annotations: continue owner = None kind = None cluster = None for kvp in lb.annotations['key_value_pair'] or []: if kvp['key'] == 'cluster': cluster = kvp['value'] elif kvp['key'] == 'owner': owner = kvp['value'] elif kvp['key'] == 'kind': kind = kvp['value'] if cluster == vnc_kube_config.cluster_name() and \ owner == 'k8s' and \ kind == self._k8s_event_type: self._create_service_event('delete', uuid, lb) break return
def _read_allocated_floating_ips(self, service_id): floating_ips = set() lb = LoadbalancerKM.get(service_id) if not lb: return vmi_ids = lb.virtual_machine_interfaces if vmi_ids is None: return None interface_found = False for vmi_id in vmi_ids: vmi = VirtualMachineInterfaceKM.get(vmi_id) if vmi is not None: interface_found = True break if not interface_found: return fip_ids = vmi.floating_ips if fip_ids is None: return None for fip_id in list(fip_ids): fip = FloatingIpKM.get(fip_id) if fip is not None: floating_ips.add(fip.address) return floating_ips
def _remove_pod_from_service(self, service_id, pod_id, port=None): lb = LoadbalancerKM.get(service_id) if not lb: return for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member and member.vm == pod_id: self.logger.debug( "Delete LB member for Pod/VM: %s from LB: %s" % (pod_id, lb.name)) try: vmi_obj = self._vnc_lib.virtual_machine_interface_read( id=member.vmi) # Remove service member label from vmi. svc_member_label = self._labels.get_service_label( lb.service_name) for k, v in svc_member_label.items(): self._vnc_lib.unset_tag(vmi_obj, k) except NoIdError: # VMI has already been deleted. Nothing to unset/remove. pass self.service_lb_member_mgr.delete(member_id) LoadbalancerMemberKM.delete(member.uuid) break
def update_ingress_backend(self, ns_name, service_name, oper): ingress_ids = self._find_ingress(self._ingress_label_cache, ns_name, service_name) for ingress_id in ingress_ids or []: ingress = IngressKM.get(ingress_id) lb = LoadbalancerKM.get(ingress_id) if not ingress or not lb: continue if oper == 'ADD': new_backend_list = self._get_new_backend_list( ingress.spec, ns_name) for new_backend in new_backend_list[:] or []: if new_backend['member']['serviceName'] == service_name: # Create a firewall rule for ingress to this service. fw_uuid = VncIngress.add_ingress_to_service_rule( ns_name, ingress.name, service_name) lb.add_firewall_rule(fw_uuid) self._create_listener_pool_member( ns_name, lb, new_backend) else: old_backend_list = self._get_old_backend_list(lb) for old_backend in old_backend_list[:] or []: if old_backend['member']['serviceName'] == service_name: self._delete_listener(old_backend['listener_id']) # Delete rules created for this ingress to service. deleted_fw_rule_uuid =\ VncIngress.delete_ingress_to_service_rule( ns_name, ingress.name, service_name) lb.remove_firewall_rule(deleted_fw_rule_uuid)
def _add_pod_to_service(self, service_id, pod_id, port=None, address=None): lb = LoadbalancerKM.get(service_id) if not lb: return vm = VirtualMachineKM.get(pod_id) host_vmi = None if not vm: if not self._args.host_network_service: return host_vmi = self._get_vmi_from_ip(address) if host_vmi == None: return else: vm = VirtualMachine(name="host", display_name="host") vm.virtual_machine_interfaces = [host_vmi] for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for vmi_id in vm.virtual_machine_interfaces: if host_vmi == None: vmi = VirtualMachineInterfaceKM.get(vmi_id) else: vmi = self._vnc_lib.virtual_machine_interface_read( id=vmi_id) if not vmi: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member and member.vmi == vmi_id: break else: self.logger.debug( "Creating LB member for Pod/VM: %s in LB: %s with " "target-port: %d" % (vm.fq_name, lb.name, port['port'])) member_obj = self._vnc_create_member( pool, pod_id, vmi_id, port['port']) try: vmi_obj = self._vnc_lib.virtual_machine_interface_read( id=vmi_id) except: raise # Attach the service label to underlying pod vmi. self._labels.append( vmi_id, self._labels.get_service_label(lb.service_name)) # Set tags on the vmi. self._vnc_lib.set_tags( vmi_obj, self._labels.get_labels_dict(vmi_id)) LoadbalancerMemberKM.locate(member_obj.uuid)
def delete(self, service_id): lb = LoadbalancerKM.get(service_id) if not lb: return vmi_ids = lb.virtual_machine_interfaces self._vnc_lib.loadbalancer_delete(id=service_id) if vmi_ids is None: return None self._delete_virtual_interface(vmi_ids)
def _lb_create(self, service_id, service_name, service_namespace, service_ip, ports): lb = LoadbalancerKM.get(service_id) if not lb: lb_obj = self._vnc_create_lb(service_id, service_name, service_namespace, service_ip) if not lb_obj: raise NoIdError lb = LoadbalancerKM.locate(service_id) self._create_listeners(service_namespace, lb, ports)
def _lb_delete(self, service_id, service_name, service_namespace): lb = LoadbalancerKM.get(service_id) if not lb: self.logger.debug( "LB doesnot exist for (%s,%s) in cfg db, return" % (service_namespace, service_name)) return self._vnc_delete_listeners(lb) self._vnc_delete_lb(service_id) LoadbalancerKM.delete(service_id)
def _delete_lb(self, uid): lb = LoadbalancerKM.get(uid) if not lb: return # Delete rules created for this member. firewall_rules = set(lb.get_firewall_rules()) for fw_rule_uuid in firewall_rules: VncIngress.delete_ingress_to_service_rule_by_id(fw_rule_uuid) lb.remove_firewall_rule(fw_rule_uuid) self._delete_all_listeners(lb) self._vnc_delete_lb(lb) LoadbalancerKM.delete(uid)
def _remove_pod_from_service(self, service_id, pod_id, port=None): lb = LoadbalancerKM.get(service_id) if not lb: return for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member and member.vm == pod_id: self.logger.debug( "Delete LB member for Pod/VM: %s from LB: %s" % (pod_id, lb.name)) self.service_lb_member_mgr.delete(member_id) LoadbalancerMemberKM.delete(member.uuid) break
def _deallocate_floating_ips(self, service_id): lb = LoadbalancerKM.get(service_id) if not lb: return vmi_ids = lb.virtual_machine_interfaces if vmi_ids is None: return None interface_found = False for vmi_id in vmi_ids: vmi = VirtualMachineInterfaceKM.get(vmi_id) if vmi is not None: interface_found = True break if interface_found is False: return fip_ids = vmi.floating_ips.copy() for fip_id in fip_ids: try: self._vnc_lib.floating_ip_delete(id=fip_id) except NoIdError: pass
def _remove_pod_from_service(self, service_id, pod_id, port=None): lb = LoadbalancerKM.get(service_id) if not lb: return for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member and member.vm == pod_id: self.logger.debug( "Delete LB member for Pod/VM: %s from LB: %s" % (pod_id, lb.name)) try: vmi_obj = self._vnc_lib.virtual_machine_interface_read( id = member.vmi) # Remove service member label from vmi. svc_member_label = self._labels.get_service_label( lb.service_name) for k,v in svc_member_label.iteritems(): self._vnc_lib.unset_tag(vmi_obj, k) except NoIdError: # VMI has already been deleted. Nothing to unset/remove. pass except: raise self.service_lb_member_mgr.delete(member_id) LoadbalancerMemberKM.delete(member.uuid) break
def _create_lb(self, uid, name, ns_name, event): annotations = event['object']['metadata'].get('annotations') ingress_controller = 'opencontrail' if annotations: if 'kubernetes.io/ingress.class' in annotations: ingress_controller = annotations['kubernetes.io/ingress.class'] if ingress_controller != 'opencontrail': self._logger.warning( "%s - ingress controller is not opencontrail for ingress %s" % (self._name, name)) self._delete_ingress(uid) return lb = LoadbalancerKM.get(uid) if not lb: lb_obj = self._vnc_create_lb(uid, name, ns_name, annotations) if lb_obj is None: return lb = LoadbalancerKM.locate(uid) else: external_ip = None if annotations and 'externalIP' in annotations: external_ip = annotations['externalIP'] specified_fip_pool_fq_name_str = None if annotations and 'opencontrail.org/fip-pool' in annotations: specified_fip_pool_fq_name_str = annotations[ 'opencontrail.org/fip-pool'] if external_ip != lb.external_ip: self._deallocate_floating_ip(lb) lb_obj = self._vnc_lib.loadbalancer_read(id=lb.uuid) fip = self._update_floating_ip(name, ns_name, external_ip, lb_obj, specified_fip_pool_fq_name_str) if fip: lb.external_ip = external_ip self._update_kube_api_server(name, ns_name, lb_obj, fip) self._clear_ingress_cache_uuid(self._ingress_label_cache, uid) spec = event['object']['spec'] new_backend_list = self._get_new_backend_list(spec, ns_name) old_backend_list = self._get_old_backend_list(lb) # find the unchanged backends for new_backend in new_backend_list[:] or []: self._update_ingress_cache(self._ingress_label_cache, ns_name, new_backend['member']['serviceName'], uid) for old_backend in old_backend_list[:] or []: if (new_backend['annotations'] == old_backend['annotations'] and new_backend['listener'] == old_backend['listener'] and new_backend['pool'] == old_backend['pool'] and new_backend['member'] == old_backend['member']): # Create a firewall rule for this member. fw_uuid = VncIngress.add_ingress_to_service_rule( ns_name, name, new_backend['member']['serviceName']) lb.add_firewall_rule(fw_uuid) old_backend_list.remove(old_backend) new_backend_list.remove(new_backend) break if len(old_backend_list) == 0 and len(new_backend_list) == 0: return lb # find the updated backends and update backend_update_list = [] for new_backend in new_backend_list[:] or []: for old_backend in old_backend_list[:] or []: if (new_backend['annotations'] == old_backend['annotations'] and new_backend['listener'] == old_backend['listener'] and new_backend['pool'] == old_backend['pool']): backend = old_backend backend['member']['member_id'] = old_backend['member_id'] backend['member']['serviceName'] = new_backend['member'][ 'serviceName'] backend['member']['servicePort'] = new_backend['member'][ 'servicePort'] backend_update_list.append(backend) old_backend_list.remove(old_backend) new_backend_list.remove(new_backend) for backend in backend_update_list or []: ll = LoadbalancerListenerKM.get(backend['listener_id']) pool = LoadbalancerPoolKM.get(backend['pool_id']) backend_member = backend['member'] member = self._update_member(ns_name, backend_member, pool) if member is None: self._logger.error("%s - Deleting Listener %s and Pool %s" % (self._name, ll.name, pool.name)) self._vnc_delete_pool(pool.uuid) LoadbalancerPoolKM.delete(pool.uuid) self._vnc_delete_listener(ll.uuid) LoadbalancerListenerKM.delete(ll.uuid) if len(old_backend_list) == 0 and len(new_backend_list) == 0: return lb # delete the old backends for backend in old_backend_list or []: self._delete_listener(backend['listener_id']) deleted_fw_rule_uuid =\ VncIngress.delete_ingress_to_service_rule( ns_name, name, backend['member']['serviceName']) lb.remove_firewall_rule(deleted_fw_rule_uuid) # create the new backends for backend in new_backend_list: # Create a firewall rule for this member. fw_uuid = VncIngress.add_ingress_to_service_rule( ns_name, name, backend['member']['serviceName']) lb.add_firewall_rule(fw_uuid) self._create_listener_pool_member(ns_name, lb, backend) return lb
def _add_pod_to_service(self, service_id, pod_id, port=None, address=None): lb = LoadbalancerKM.get(service_id) if not lb: return vm = VirtualMachineKM.get(pod_id) host_vmi = None if not vm: if not self._args.host_network_service: return host_vmi = self._get_vmi_from_ip(address) if host_vmi is None: return else: vm = VirtualMachine(name="host", display_name="host") vm.virtual_machine_interfaces = [host_vmi] for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for vmi_id in vm.virtual_machine_interfaces: vmi = VirtualMachineInterfaceKM.get(vmi_id) if not vmi: continue if host_vmi is None: # Add VMI only if it matches the default address for endpoint, # ignore other interfaces for pod ip_found = False for iip_uuid in vmi.instance_ips: iip = InstanceIpKM.get(iip_uuid) if iip and iip.address == address: ip_found = True break if not ip_found: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member and member.vmi == vmi_id: break else: self.logger.debug( "Creating LB member for Pod/VM: %s in LB: %s with " "target-port: %d" % (vm.fq_name, lb.name, port['port'])) member_obj = self._vnc_create_member( pool, pod_id, vmi_id, port['port']) vmi_obj = self._vnc_lib.virtual_machine_interface_read( id=vmi_id) # Attach the service label to underlying pod vmi. self._labels.append( vmi_id, self._labels.get_service_label(lb.service_name)) # Set tags on the vmi. self._vnc_lib.set_tags( vmi_obj, self._labels.get_labels_dict(vmi_id)) LoadbalancerMemberKM.locate(member_obj.uuid)
def _allocate_floating_ips(self, service_id, specified_fip_pool_fq_name_str, service_namespace, external_ips=set()): lb = LoadbalancerKM.get(service_id) if not lb: return None vmi_ids = lb.virtual_machine_interfaces if vmi_ids is None: return None interface_found = False for vmi_id in vmi_ids: vmi = VirtualMachineInterfaceKM.get(vmi_id) if vmi is not None: interface_found = True break if not interface_found: return vmi_obj = self._vnc_lib.virtual_machine_interface_read(id=vmi_id) if vmi_obj is None: return None fip_pool = None if specified_fip_pool_fq_name_str is not None: fip_pool = self._get_specified_fip_pool( specified_fip_pool_fq_name_str) if fip_pool is None and self._get_annotated_ns_fip_pool( service_namespace) is not None: fip_pool = self._get_annotated_ns_fip_pool(service_namespace) if fip_pool is None: fip_pool = self._get_public_fip_pool() if fip_pool is None: self.logger.warning("public_fip_pool doesn't exists") return None def _check_ip_with_fip_pool(external_ip, fip_pool_obj): try: vn_obj = self._vnc_lib.virtual_network_read( id=fip_pool_obj.parent_uuid) except NoIdError: return True ipam_refs = vn_obj.__dict__.get('network_ipam_refs', []) for ipam_ref in ipam_refs: vnsn_data = ipam_ref['attr'].__dict__ ipam_subnets = vnsn_data.get('ipam_subnets', []) for ipam_subnet in ipam_subnets: subnet_dict = ipam_subnet.__dict__.get('subnet', {}) if 'ip_prefix' in subnet_dict.__dict__: ip_subnet_str = ( subnet_dict.__dict__.get('ip_prefix', '') + '/' + str(subnet_dict.__dict__.get('ip_prefix_len'))) if IPAddress(external_ip) in IPNetwork(ip_subnet_str): return True self.logger.error("external_ip not in fip_pool subnet") return False def _allocate_floating_ip(lb, vmi, fip_pool, external_ip=None): fip_obj = FloatingIp(lb.name + str(external_ip) + "-externalIP", fip_pool) fip_obj.set_virtual_machine_interface(vmi_obj) if external_ip: if not (_check_ip_with_fip_pool(external_ip, fip_pool)): err_str = "external_ip " + external_ip + " not in fip_pool subnet" self.logger.error(err_str) return None fip_obj.set_floating_ip_address(external_ip) project = self._vnc_lib.project_read(id=lb.parent_uuid) fip_obj.set_project(project) try: self._vnc_lib.floating_ip_create(fip_obj) except RefsExistError: string_buf = StringIO() cgitb_hook(file=string_buf, format="text") err_msg = string_buf.getvalue() self.logger.error("%s" % (err_msg)) except Exception: string_buf = StringIO() cgitb_hook(file=string_buf, format="text") err_msg = string_buf.getvalue() self.logger.error("%s" % (err_msg)) fip = FloatingIpKM.locate(fip_obj.uuid) self.logger.notice("floating ip allocated : %s for Service (%s)" % (fip.address, service_id)) return (fip.address) fips = set() if len(external_ips) == 0: fip_addr = _allocate_floating_ip(lb, vmi, fip_pool) if fip_addr: fips.add(fip_addr) return fips for external_ip in external_ips: fip_addr = _allocate_floating_ip(lb, vmi, fip_pool, external_ip) if fip_addr: fips.add(fip_addr) return fips
def _add_pod_to_service(self, service_id, pod_id, port=None, address=None): lb = LoadbalancerKM.get(service_id) if not lb: return vm = VirtualMachineKM.get(pod_id) host_vmi = None if not vm: if not self._args.host_network_service: return host_vmi = self._get_vmi_from_ip(address) if host_vmi == None: return else: vm = VirtualMachine(name="host", display_name="host") vm.virtual_machine_interfaces = [host_vmi] for lb_listener_id in lb.loadbalancer_listeners: pool = self._get_loadbalancer_pool(lb_listener_id, port) if not pool: continue for vmi_id in vm.virtual_machine_interfaces: if host_vmi == None: vmi = VirtualMachineInterfaceKM.get(vmi_id) else: vmi = self._vnc_lib.virtual_machine_interface_read(id=vmi_id) if not vmi: continue # Add VMI only if it matches the default address for endpoint, # ignore other interfaces for pod ip_found = False for iip_uuid in vmi.instance_ips: iip = InstanceIpKM.get(iip_uuid) if iip and iip.address == address: ip_found = True break if ip_found == False: continue for member_id in pool.members: member = LoadbalancerMemberKM.get(member_id) if member and member.vmi == vmi_id: break else: self.logger.debug( "Creating LB member for Pod/VM: %s in LB: %s with " "target-port: %d" % (vm.fq_name, lb.name, port['port'])) member_obj = self._vnc_create_member( pool, pod_id, vmi_id, port['port']) try: vmi_obj = self._vnc_lib.virtual_machine_interface_read( id = vmi_id) except: raise # Attach the service label to underlying pod vmi. self._labels.append(vmi_id, self._labels.get_service_label(lb.service_name)) # Set tags on the vmi. self._vnc_lib.set_tags(vmi_obj, self._labels.get_labels_dict(vmi_id)) LoadbalancerMemberKM.locate(member_obj.uuid)