예제 #1
0
    def sync_pods(self, pods):
        expected_logical_ports = set()
        pods = pods.get('items', [])
        for pod in pods:
            pod_name = pod['metadata']['name']
            namespace = pod['metadata']['namespace']
            logical_port = "%s_%s" % (namespace, pod_name)
            expected_logical_ports.add(logical_port)

        try:
            existing_logical_ports = ovn_nbctl(
                                "--data=bare", "--no-heading",
                                "--columns=name", "find",
                                "logical_switch_port",
                                "external_id:pod=true").split()
            existing_logical_ports = set(existing_logical_ports)
        except Exception as e:
            vlog.err("sync_pods: find failed %s" % (str(e)))
            return

        for logical_port in existing_logical_ports - expected_logical_ports:
            try:
                ovn_nbctl("--if-exists", "lsp-del", logical_port)
            except Exception as e:
                vlog.err("sync_pods: failed to delete logical_port %s"
                         % (logical_port))
                continue

            vlog.info("sync_pods: Deleted logical port %s"
                      % (logical_port))
예제 #2
0
    def _create_load_balancer_vip(self, load_balancer, service_ip, ips, port,
                                  target_port, protocol):
        # With service_ip:port as a VIP, create an entry in 'load_balancer'

        vlog.dbg(
            "received event to create/modify load_balancer (%s) vip "
            "service_ip=%s, ips=%s, port=%s, target_port=%s, protocol=%s" %
            (load_balancer, service_ip, ips, port, target_port, protocol))
        if not port or not target_port or not protocol or not load_balancer:
            return

        # key is of the form "IP:port" (with quotes around)
        key = "\"" + service_ip + ":" + str(port) + "\""
        if not ips:
            try:
                ovn_nbctl("remove", "load_balancer", load_balancer, "vips",
                          key)
            except Exception as e:
                vlog.err("_create_load_balancer_vip remove: (%s)" % (str(e)))
            return

        # target is of the form "IP1:port, IP2:port, IP3:port"
        target_endpoints = ",".join(
            ["%s:%s" % (ip, target_port) for ip in ips])
        target = "\"" + target_endpoints + "\""

        try:
            ovn_nbctl("set", "load_balancer", load_balancer,
                      "vips:" + key + "=" + target)
        except Exception as e:
            vlog.err("_create_load_balancer_vip add: (%s)" % (str(e)))
예제 #3
0
    def sync_pods(self, pods):
        expected_logical_ports = set()
        pods = pods.get('items', [])
        for pod in pods:
            pod_name = pod['metadata']['name']
            namespace = pod['metadata']['namespace']
            logical_port = "%s_%s" % (namespace, pod_name)
            expected_logical_ports.add(logical_port)

        try:
            existing_logical_ports = ovn_nbctl("--data=bare", "--no-heading",
                                               "--columns=name", "find",
                                               "logical_switch_port",
                                               "external_id:pod=true").split()
            existing_logical_ports = set(existing_logical_ports)
        except Exception as e:
            vlog.err("sync_pods: find failed %s" % (str(e)))
            return

        for logical_port in existing_logical_ports - expected_logical_ports:
            try:
                ovn_nbctl("--if-exists", "lsp-del", logical_port)
            except Exception as e:
                vlog.err("sync_pods: failed to delete logical_port %s" %
                         (logical_port))
                continue

            vlog.info("sync_pods: Deleted logical port %s" % (logical_port))
예제 #4
0
    def sync_pods(self, pods):
        expected_logical_ports = set()
        pods = pods.get('items', [])
        for pod in pods:
            pod_name = pod['metadata']['name']
            namespace = pod['metadata']['namespace']
            logical_port = "%s_%s" % (namespace, pod_name)
            annotations = pod['metadata']['annotations']
            expected_logical_ports.add(logical_port)

            # We should sync the container port names as there are no
            # guarantees that a endpoint creation event will become after
            # all the pods creation events.
            ip_address = self._get_ip_address_from_annotations(annotations)
            if ip_address:
                self._add_k8s_l4_port_name_cache(pod, ip_address)

        try:
            existing_logical_ports = ovn_nbctl(
                "--data=bare", "--no-heading", "--columns=name", "find",
                "logical_switch_port", "external-ids:pod=true").split()
            existing_logical_ports = set(existing_logical_ports)
        except Exception as e:
            vlog.err("sync_pods: find failed %s" % (str(e)))
            return

        for logical_port in existing_logical_ports - expected_logical_ports:
            try:
                ovn_nbctl("--if-exists", "lsp-del", logical_port)
            except Exception as e:
                vlog.err("sync_pods: failed to delete logical_port %s" %
                         (logical_port))
                continue

            vlog.info("sync_pods: Deleted logical port %s" % (logical_port))
예제 #5
0
 def _delete_load_balancer_vip(self, load_balancer, vip):
     # Remove the 'vip' from the 'load_balancer'.
     try:
         ovn_nbctl("remove", "load_balancer", load_balancer, "vips", vip)
         vlog.info("deleted vip %s from %s" % (vip, load_balancer))
     except Exception as e:
         vlog.err("_delete_load_balancer_vip: failed to remove vip %s "
                  " from %s (%s)" % (vip, load_balancer, str(e)))
예제 #6
0
 def _delete_load_balancer_vip(self, load_balancer, vip):
     # Remove the 'vip' from the 'load_balancer'.
     try:
         ovn_nbctl("remove", "load_balancer", load_balancer, "vips", vip)
         vlog.info("deleted vip %s from %s" % (vip, load_balancer))
     except Exception as e:
         vlog.err("_delete_load_balancer_vip: failed to remove vip %s "
                  " from %s (%s)" % (vip, load_balancer, str(e)))
예제 #7
0
    def _create_load_balancer_vip(self, namespace, load_balancer, service_ip,
                                  ips, port, target_port, protocol):
        # With service_ip:port as a VIP, create an entry in 'load_balancer'

        vlog.dbg(
            "received event to create/modify load_balancer (%s) vip "
            "service_ip=%s, ips=%s, port=%s, target_port=%s, protocol=%s" %
            (load_balancer, service_ip, ips, port, target_port, protocol))
        if not port or not target_port or not protocol or not load_balancer:
            return

        # key is of the form "IP:port" (with quotes around)
        key = "\"" + service_ip + ":" + str(port) + "\""
        if not ips:
            try:
                ovn_nbctl("remove", "load_balancer", load_balancer, "vips",
                          key)
            except Exception as e:
                vlog.err("_create_load_balancer_vip remove: (%s)" % (str(e)))
            return

        if target_port.isdigit():
            # target is of the form "IP1:port, IP2:port, IP3:port"
            target_endpoints = ",".join(
                ["%s:%s" % (ip, target_port) for ip in ips])
        else:
            # 'target_port' is a string.  We should get its number
            # from the cache.
            if not self.port_name_cache.get(namespace):
                vlog.warn("targetPort of %s in ns %s does not have an "
                          "associated port. Ignoring endpoint creation." %
                          (target_port, namespace))
                return
            target_endpoint_list = []
            for ip in ips:
                if not self.port_name_cache[namespace].get(ip):
                    continue

                num_port = self.port_name_cache[namespace][ip].get(target_port)
                if not num_port:
                    continue

                target_endpoint_list.append("%s:%s" % (ip, num_port))

            if not target_endpoint_list:
                vlog.warn("targetPort of %s in ns %s does not have any "
                          "associated ports. Ignoring endpoint creation." %
                          (target_port, namespace))
                return
            target_endpoints = ",".join(target_endpoint_list)

        target = "\"" + target_endpoints + "\""

        try:
            ovn_nbctl("set", "load_balancer", load_balancer,
                      "vips:" + key + "=" + target)
        except Exception as e:
            vlog.err("_create_load_balancer_vip add: (%s)" % (str(e)))
예제 #8
0
    def _create_load_balancer_vip(self, namespace, load_balancer, service_ip,
                                  ips, port, target_port, protocol):
        # With service_ip:port as a VIP, create an entry in 'load_balancer'

        vlog.dbg("received event to create/modify load_balancer (%s) vip "
                 "service_ip=%s, ips=%s, port=%s, target_port=%s, protocol=%s"
                 % (load_balancer, service_ip, ips, port, target_port,
                    protocol))
        if not port or not target_port or not protocol or not load_balancer:
            return

        # key is of the form "IP:port" (with quotes around)
        key = "\"" + service_ip + ":" + str(port) + "\""
        if not ips:
            try:
                ovn_nbctl("remove", "load_balancer", load_balancer,
                          "vips", key)
            except Exception as e:
                vlog.err("_create_load_balancer_vip remove: (%s)" % (str(e)))
            return

        if target_port.isdigit():
            # target is of the form "IP1:port, IP2:port, IP3:port"
            target_endpoints = ",".join(["%s:%s" % (ip, target_port)
                                         for ip in ips])
        else:
            # 'target_port' is a string.  We should get its number
            # from the cache.
            if not self.port_name_cache.get(namespace):
                vlog.warn("targetPort of %s in ns %s does not have an "
                          "associated port. Ignoring endpoint creation."
                          % (target_port, namespace))
                return
            target_endpoint_list = []
            for ip in ips:
                if not self.port_name_cache[namespace].get(ip):
                    continue

                num_port = self.port_name_cache[namespace][ip].get(target_port)
                if not num_port:
                    continue

                target_endpoint_list.append("%s:%s" % (ip, num_port))

            if not target_endpoint_list:
                vlog.warn("targetPort of %s in ns %s does not have any "
                          "associated ports. Ignoring endpoint creation."
                          % (target_port, namespace))
                return
            target_endpoints = ",".join(target_endpoint_list)

        target = "\"" + target_endpoints + "\""

        try:
            ovn_nbctl("set", "load_balancer", load_balancer,
                      "vips:" + key + "=" + target)
        except Exception as e:
            vlog.err("_create_load_balancer_vip add: (%s)" % (str(e)))
예제 #9
0
def ovn_init_overlay():
    OVN_NB = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", "external_ids:ovn-nb").strip('"')
    if not OVN_NB:
        sys.exit("OVN central database's ip address not set")
    variables.OVN_NB = OVN_NB

    K8S_API_SERVER = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", "external_ids:k8s-api-server").strip('"')
    if not K8S_API_SERVER:
        sys.exit("K8S_API_SERVER not set")
    if not K8S_API_SERVER.startswith("http"):
        variables.K8S_API_SERVER = "http://%s" % K8S_API_SERVER
    else:
        variables.K8S_API_SERVER = K8S_API_SERVER

    K8S_CLUSTER_ROUTER = ovn_nbctl(
        "--data=bare",
        "--no-heading",
        "--columns=_uuid",
        "find",
        "logical_router",
        "external_ids:k8s-cluster-router=yes",
    )
    if not K8S_CLUSTER_ROUTER:
        sys.exit("K8S_CLUSTER_ROUTER not set")
    variables.K8S_CLUSTER_ROUTER = K8S_CLUSTER_ROUTER

    K8S_CLUSTER_LB_TCP = ovn_nbctl(
        "--data=bare", "--no-heading", "--columns=_uuid", "find", "load_balancer", "external_ids:k8s-cluster-lb-tcp=yes"
    )
    if not K8S_CLUSTER_LB_TCP:
        sys.exit("K8S_CLUSTER_LB_TCP not set")
    variables.K8S_CLUSTER_LB_TCP = K8S_CLUSTER_LB_TCP

    K8S_CLUSTER_LB_UDP = ovn_nbctl(
        "--data=bare", "--no-heading", "--columns=_uuid", "find", "load_balancer", "external_ids:k8s-cluster-lb-udp=yes"
    )
    if not K8S_CLUSTER_LB_UDP:
        sys.exit("K8S_CLUSTER_LB_UDP not set")
    variables.K8S_CLUSTER_LB_UDP = K8S_CLUSTER_LB_UDP

    K8S_NS_LB_TCP = ovn_nbctl(
        "--data=bare", "--no-heading", "--columns=_uuid", "find", "load_balancer", "external_ids:k8s-ns-lb-tcp=yes"
    )
    variables.K8S_NS_LB_TCP = K8S_NS_LB_TCP

    K8S_NS_LB_UDP = ovn_nbctl(
        "--data=bare", "--no-heading", "--columns=_uuid", "find", "load_balancer", "external_ids:k8s-ns-lb-udp=yes"
    )
    variables.K8S_NS_LB_UDP = K8S_NS_LB_UDP

    variables.OVN_MODE = "overlay"
예제 #10
0
def ovn_init_overlay():
    OVN_NB = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".",
                       "external_ids:ovn-nb").strip('"')
    if not OVN_NB:
        sys.exit("OVN central database's ip address not set")
    variables.OVN_NB = OVN_NB

    K8S_API_SERVER = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".",
                               "external_ids:k8s-api-server").strip('"')
    if not K8S_API_SERVER:
        sys.exit("K8S_API_SERVER not set")
    if not K8S_API_SERVER.startswith("http"):
        variables.K8S_API_SERVER = "http://%s" % K8S_API_SERVER
    else:
        variables.K8S_API_SERVER = K8S_API_SERVER

    K8S_CLUSTER_ROUTER = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "logical_router",
                                   "external_ids:k8s-cluster-router=yes")
    if not K8S_CLUSTER_ROUTER:
        sys.exit("K8S_CLUSTER_ROUTER not set")
    variables.K8S_CLUSTER_ROUTER = K8S_CLUSTER_ROUTER

    K8S_CLUSTER_LB_TCP = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "load_balancer",
                                   "external_ids:k8s-cluster-lb-tcp=yes")
    if not K8S_CLUSTER_LB_TCP:
        sys.exit("K8S_CLUSTER_LB_TCP not set")
    variables.K8S_CLUSTER_LB_TCP = K8S_CLUSTER_LB_TCP

    K8S_CLUSTER_LB_UDP = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "load_balancer",
                                   "external_ids:k8s-cluster-lb-udp=yes")
    if not K8S_CLUSTER_LB_UDP:
        sys.exit("K8S_CLUSTER_LB_UDP not set")
    variables.K8S_CLUSTER_LB_UDP = K8S_CLUSTER_LB_UDP

    K8S_NS_LB_TCP = ovn_nbctl("--data=bare", "--no-heading",
                              "--columns=_uuid", "find", "load_balancer",
                              "external_ids:k8s-ns-lb-tcp=yes")
    variables.K8S_NS_LB_TCP = K8S_NS_LB_TCP

    K8S_NS_LB_UDP = ovn_nbctl("--data=bare", "--no-heading",
                              "--columns=_uuid", "find", "load_balancer",
                              "external_ids:k8s-ns-lb-udp=yes")
    variables.K8S_NS_LB_UDP = K8S_NS_LB_UDP

    variables.OVN_MODE = "overlay"
예제 #11
0
    def _get_switch_gateway_ip(self, logical_switch):
        cached_logical_switch = self.logical_switch_cache.get(logical_switch,
                                                              {})
        if cached_logical_switch:
            gateway_ip_mask = cached_logical_switch.get('gateway_ip_mask')
        else:
            try:
                gateway_ip_mask = ovn_nbctl("--if-exists", "get",
                                            "logical_switch", logical_switch,
                                            "external_ids:gateway_ip"
                                            ).strip('"')
            except Exception as e:
                vlog.err("_get_switch_gateway_ip: failed to get gateway_ip %s"
                         % (str(e)))
                return (None, None)

        try:
            (gateway_ip, mask) = gateway_ip_mask.split('/')
        except Exception as e:
            vlog.err("_get_switch_gateway_ip: failed to split ip/mask %s"
                     % (gateway_ip_mask))
            return (None, None)

        if not cached_logical_switch:
            self.logical_switch_cache[logical_switch] = {'gateway_ip_mask':
                                                         gateway_ip_mask}
        return (gateway_ip, mask)
예제 #12
0
    def _create_external_vip(self, external_ip, ips, port, target_port,
                             protocol):
        # With external_ip:port as the VIP, create an entry in a gateway
        # load-balancer.

        # Get the gateway where we can add external_ip:port as a VIP.
        physical_gateway = self._get_ovn_external_ip_gateway()
        if not physical_gateway:
            return

        try:
            # Get the load-balancer instantiated in the gateway.
            external_id_key = protocol + "_lb_gateway_router"
            load_balancer = ovn_nbctl(
                "--data=bare", "--no-heading", "--columns=_uuid", "find",
                "load_balancer", "external_ids:" + external_id_key + "=" +
                physical_gateway).strip('"')
        except Exception as e:
            vlog.err("_create_external_vip: get failed for"
                     " %s (%s)" % (physical_gateway, str(e)))
            return

            if not load_balancer:
                vlog.warn("physical gateway %s does not have a load_balancer" %
                          (physical_gateway))

        # With external_ip:port as VIP, add an entry in 'load_balancer'.
        self._create_load_balancer_vip(load_balancer, external_ip, ips, port,
                                       target_port, protocol)
예제 #13
0
    def _create_external_vip(self, namespace, external_ip, ips,
                             port, target_port, protocol):
        # With external_ip:port as the VIP, create an entry in a gateway
        # load-balancer.

        # Get the gateway where we can add external_ip:port as a VIP.
        physical_gateway = self._get_ovn_external_ip_gateway()
        if not physical_gateway:
            return

        try:
            # Get the load-balancer instantiated in the gateway.
            external_id_key = protocol + "_lb_gateway_router"
            load_balancer = ovn_nbctl("--data=bare", "--no-heading",
                                      "--columns=_uuid", "find",
                                      "load_balancer",
                                      "external_ids:" + external_id_key + "=" +
                                      physical_gateway).strip('"')
        except Exception as e:
            vlog.err("_create_external_vip: get failed for"
                     " %s (%s)" % (physical_gateway, str(e)))
            return

            if not load_balancer:
                vlog.warn("physical gateway %s does not have a load_balancer"
                          % (physical_gateway))

        # With external_ip:port as VIP, add an entry in 'load_balancer'.
        self._create_load_balancer_vip(namespace, load_balancer, external_ip,
                                       ips, port, target_port, protocol)
예제 #14
0
    def _get_switch_gateway_ip(self, logical_switch):
        cached_logical_switch = self.logical_switch_cache.get(
            logical_switch, {})
        if cached_logical_switch:
            gateway_ip_mask = cached_logical_switch.get('gateway_ip_mask')
        else:
            try:
                gateway_ip_mask = ovn_nbctl(
                    "--if-exists", "get", "logical_switch", logical_switch,
                    "external_ids:gateway_ip").strip('"')
            except Exception as e:
                vlog.err(
                    "_get_switch_gateway_ip: failed to get gateway_ip %s" %
                    (str(e)))
                return (None, None)

        try:
            (gateway_ip, mask) = gateway_ip_mask.split('/')
        except Exception as e:
            vlog.err("_get_switch_gateway_ip: failed to split ip/mask %s" %
                     (gateway_ip_mask))
            return (None, None)

        if not cached_logical_switch:
            self.logical_switch_cache[logical_switch] = {
                'gateway_ip_mask': gateway_ip_mask
            }
        return (gateway_ip, mask)
예제 #15
0
    def _create_gateways_vip(self, namespace, ips, port, target_port,
                             protocol):
        # Each gateway has a separate load-balancer for N/S traffic

        physical_gateways = self._get_ovn_gateways()
        if not physical_gateways:
            return

        for physical_gateway in physical_gateways:
            # Go through each gateway to get its physical_ip and load-balancer.
            try:
                physical_ip = ovn_nbctl(
                                    "get", "logical_router", physical_gateway,
                                    "external_ids:physical_ip").strip('"')
            except Exception as e:
                vlog.err("_create_gateways_vip: get failed for"
                         " %s (%s)" % (physical_gateway, str(e)))
                continue

            if not physical_ip:
                vlog.warn("physical gateway %s does not have physical ip"
                          % (physical_ip))
                continue

            try:
                external_id_key = protocol + "_lb_gateway_router"
                load_balancer = ovn_nbctl(
                                    "--data=bare", "--no-heading",
                                    "--columns=_uuid", "find", "load_balancer",
                                    "external_ids:" + external_id_key + "=" +
                                    physical_gateway
                                    ).strip('"')
            except Exception as e:
                vlog.err("_create_gateways_vip: find failed for"
                         " %s (%s)" % (physical_gateway, str(e)))
                continue

            if not load_balancer:
                vlog.warn("physical gateway %s does not have load_balancer"
                          % (physical_gateway))
                continue

            # With the physical_ip:port as the VIP, add an entry in
            # 'load_balancer'.
            self._create_load_balancer_vip(namespace, load_balancer,
                                           physical_ip, ips,
                                           port, target_port, protocol)
예제 #16
0
    def _create_gateways_vip(self, namespace, ips, port, target_port,
                             protocol):
        # Each gateway has a separate load-balancer for N/S traffic

        physical_gateways = self._get_ovn_gateways()
        if not physical_gateways:
            return

        for physical_gateway in physical_gateways:
            # Go through each gateway to get its physical_ip and load-balancer.
            try:
                physical_ip = ovn_nbctl(
                                    "get", "logical_router", physical_gateway,
                                    "external_ids:physical_ip").strip('"')
            except Exception as e:
                vlog.err("_create_gateways_vip: get failed for"
                         " %s (%s)" % (physical_gateway, str(e)))
                continue

            if not physical_ip:
                vlog.warn("physical gateway %s does not have physical ip"
                          % (physical_ip))
                continue

            try:
                external_id_key = protocol + "_lb_gateway_router"
                load_balancer = ovn_nbctl(
                                    "--data=bare", "--no-heading",
                                    "--columns=_uuid", "find", "load_balancer",
                                    "external_ids:" + external_id_key + "=" +
                                    physical_gateway
                                    ).strip('"')
            except Exception as e:
                vlog.err("_create_gateways_vip: find failed for"
                         " %s (%s)" % (physical_gateway, str(e)))
                continue

            if not load_balancer:
                vlog.warn("physical gateway %s does not have load_balancer"
                          % (physical_gateway))
                continue

            # With the physical_ip:port as the VIP, add an entry in
            # 'load_balancer'.
            self._create_load_balancer_vip(namespace, load_balancer,
                                           physical_ip, ips,
                                           port, target_port, protocol)
예제 #17
0
    def delete_logical_port(self, event):
        data = event.metadata
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not pod_name:
            vlog.err("absent pod name in pod %s. "
                     "unable to delete logical port" % data)
            return

        try:
            ovn_nbctl("--if-exists", "lsp-del", logical_port)
        except Exception:
            vlog.exception("failure in delete_logical_port: lsp-del")
            return

        vlog.info("deleted logical port %s" % logical_port)
예제 #18
0
    def delete_logical_port(self, event):
        data = event.metadata
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not logical_port:
            vlog.err("absent pod name in pod %s. "
                     "Not creating logical port" % (data))
            return

        try:
            ovn_nbctl("--if-exists", "lsp-del", logical_port)
        except Exception as e:
            vlog.err("_delete_logical_port: lsp-add (%s)" % (str(e)))
            return

        vlog.dbg("deleted logical port %s" % (logical_port))
예제 #19
0
    def delete_logical_port(self, event):
        data = event.metadata
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not pod_name:
            vlog.err("absent pod name in pod %s. "
                     "unable to delete logical port" % data)
            return

        try:
            ovn_nbctl("--if-exists", "lsp-del", logical_port)
        except Exception:
            vlog.exception("failure in delete_logical_port: lsp-del")
            return

        vlog.info("deleted logical port %s" % logical_port)
예제 #20
0
    def _create_load_balancer_vip(self, service_type, service_ip, ips, port,
                                  target_port, protocol):
        vlog.dbg("received event to create load_balancer vip")
        if not port or not target_port or not protocol or not service_type:
            return

        load_balancer = ""
        if protocol == "TCP" and service_type == "ClusterIP":
            load_balancer = variables.K8S_CLUSTER_LB_TCP

        if protocol == "UDP" and service_type == "ClusterIP":
            load_balancer = variables.K8S_CLUSTER_LB_UDP

        if protocol == "TCP" and service_type == "NodePort":
            load_balancer = variables.K8S_NS_LB_TCP

        if protocol == "UDP" and service_type == "NodePort":
            load_balancer = variables.K8S_NS_LB_UDP

        if not load_balancer:
            return

        # key is of the form "IP:port" (with quotes around)
        key = "\"" + service_ip + ":" + str(port) + "\""
        if not ips:
            try:
                ovn_nbctl("remove", "load_balancer", load_balancer, "vips",
                          key)
            except Exception as e:
                vlog.err("_create_load_balancer_vip remove: (%s)" % (str(e)))
            return

        # target is of the form "IP1:port, IP2:port, IP3:port"
        target = ""
        for ip in ips:
            target = target + ip + ":" + str(target_port) + ","
        target = target[:-1]
        target = "\"" + target + "\""

        try:
            ovn_nbctl("set", "load_balancer", load_balancer,
                      "vips:" + key + "=" + target)
        except Exception as e:
            vlog.err("_create_load_balancer_vip add: (%s)" % (str(e)))
예제 #21
0
 def _get_load_balancer_vips(self, load_balancer):
     try:
         vips = ovn_nbctl("--data=bare", "--no-heading", "get",
                          "load_balancer", load_balancer,
                          "vips").replace('=', ":")
         return ast.literal_eval(vips)
     except Exception as e:
         vlog.err("_get_load_balancer_vips: failed to get vips for %s (%s)"
                  % (load_balancer, str(e)))
         return None
예제 #22
0
    def _create_load_balancer_vip(self, service_type, service_ip, ips, port,
                                  target_port, protocol):
        vlog.dbg("received event to create/modify load_balancer vip with "
                 "service_type=%s, service_ip=%s, ips=%s, port=%s,"
                 "target_port=%s, protocol=%s"
                 % (service_type, service_ip, ips, port, target_port,
                    protocol))
        if not port or not target_port or not protocol or not service_type:
            return

        load_balancer = ""
        if protocol == "TCP" and service_type == "ClusterIP":
            load_balancer = variables.K8S_CLUSTER_LB_TCP
        elif protocol == "UDP" and service_type == "ClusterIP":
            load_balancer = variables.K8S_CLUSTER_LB_UDP
        elif protocol == "TCP" and service_type == "NodePort":
            load_balancer = variables.K8S_NS_LB_TCP
        elif protocol == "UDP" and service_type == "NodePort":
            load_balancer = variables.K8S_NS_LB_UDP

        if not load_balancer:
            return

        # key is of the form "IP:port" (with quotes around)
        key = "\"" + service_ip + ":" + str(port) + "\""
        if not ips:
            try:
                ovn_nbctl("remove", "load_balancer", load_balancer,
                          "vips", key)
            except Exception as e:
                vlog.err("_create_load_balancer_vip remove: (%s)" % (str(e)))
            return

        # target is of the form "IP1:port, IP2:port, IP3:port"
        target_endpoints = ",".join(["%s:%s" % (ip, target_port)
                                     for ip in ips])
        target = "\"" + target_endpoints + "\""

        try:
            ovn_nbctl("set", "load_balancer", load_balancer,
                      "vips:" + key + "=" + target)
        except Exception as e:
            vlog.err("_create_load_balancer_vip add: (%s)" % (str(e)))
예제 #23
0
 def _get_load_balancer_vips(self, load_balancer):
     try:
         vips = ovn_nbctl("--data=bare", "--no-heading", "get",
                          "load_balancer", load_balancer,
                          "vips").replace('=', ":")
         return ast.literal_eval(vips)
     except Exception as e:
         vlog.err("_get_load_balancer_vips: failed to get vips for %s (%s)"
                  % (load_balancer, str(e)))
         return None
예제 #24
0
    def _get_ovn_gateways(self):
        # Return all created gateways.
        physical_gateways = []
        try:
            physical_gateways = ovn_nbctl("--data=bare", "--no-heading",
                                          "--columns=name", "find",
                                          "logical_router",
                                          "options:chassis!=null").split()
        except Exception as e:
            vlog.err("_get_ovn_gateways: find failed %s" % (str(e)))

        return physical_gateways
예제 #25
0
    def delete_logical_port(self, event):
        data = event.metadata
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not pod_name:
            vlog.err("absent pod name in pod %s. "
                     "unable to delete logical port" % data)
            return

        annotations = data['metadata']['annotations']
        ip_address = self._get_ip_address_from_annotations(annotations)
        if ip_address:
            self._delete_k8s_l4_port_name_cache(data, ip_address)

        try:
            ovn_nbctl("--if-exists", "lsp-del", logical_port)
        except Exception:
            vlog.exception("failure in delete_logical_port: lsp-del")
            return

        vlog.info("deleted logical port %s" % logical_port)
예제 #26
0
    def delete_logical_port(self, event):
        data = event.metadata
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not pod_name:
            vlog.err("absent pod name in pod %s. "
                     "unable to delete logical port" % data)
            return

        annotations = data['metadata']['annotations']
        ip_address = self._get_ip_address_from_annotations(annotations)
        if ip_address:
            self._delete_k8s_l4_port_name_cache(data, ip_address)

        try:
            ovn_nbctl("--if-exists", "lsp-del", logical_port)
        except Exception:
            vlog.exception("failure in delete_logical_port: lsp-del")
            return

        vlog.info("deleted logical port %s" % logical_port)
예제 #27
0
    def _get_ovn_gateways(self):
        # Return all created gateways.
        physical_gateways = []
        try:
            physical_gateways = ovn_nbctl(
                                "--data=bare", "--no-heading",
                                "--columns=name", "find",
                                "logical_router",
                                "options:chassis!=null").split()
        except Exception as e:
            vlog.err("_get_ovn_gateways: find failed %s" % (str(e)))

        return physical_gateways
예제 #28
0
    def sync_pods(self, pods):
        expected_logical_ports = set()
        pods = pods.get('items', [])
        for pod in pods:
            pod_name = pod['metadata']['name']
            namespace = pod['metadata']['namespace']
            logical_port = "%s_%s" % (namespace, pod_name)
            annotations = pod['metadata']['annotations']
            expected_logical_ports.add(logical_port)

            # We should sync the container port names as there are no
            # guarantees that a endpoint creation event will become after
            # all the pods creation events.
            ip_address = self._get_ip_address_from_annotations(annotations)
            if ip_address:
                self._add_k8s_l4_port_name_cache(pod, ip_address)

        try:
            existing_logical_ports = ovn_nbctl(
                                "--data=bare", "--no-heading",
                                "--columns=name", "find",
                                "logical_switch_port",
                                "external-ids:pod=true").split()
            existing_logical_ports = set(existing_logical_ports)
        except Exception as e:
            vlog.err("sync_pods: find failed %s" % (str(e)))
            return

        for logical_port in existing_logical_ports - expected_logical_ports:
            try:
                ovn_nbctl("--if-exists", "lsp-del", logical_port)
            except Exception as e:
                vlog.err("sync_pods: failed to delete logical_port %s"
                         % (logical_port))
                continue

            vlog.info("sync_pods: Deleted logical port %s"
                      % (logical_port))
예제 #29
0
def ovn_init_overlay():
    if os.path.exists(UNIX_SOCKET):
        OVN_NB = "unix:%s" % UNIX_SOCKET
    else:
        sys.exit("OVN NB database does not have unix socket")
    variables.OVN_NB = OVN_NB

    K8S_API_SERVER = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".",
                               "external_ids:k8s-api-server").strip('"')
    if not K8S_API_SERVER:
        sys.exit("K8S_API_SERVER not set")
    if not K8S_API_SERVER.startswith("http"):
        variables.K8S_API_SERVER = "http://%s" % K8S_API_SERVER
    else:
        variables.K8S_API_SERVER = K8S_API_SERVER

    K8S_CLUSTER_ROUTER = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "logical_router",
                                   "external_ids:k8s-cluster-router=yes")
    if not K8S_CLUSTER_ROUTER:
        sys.exit("K8S_CLUSTER_ROUTER not set")
    variables.K8S_CLUSTER_ROUTER = K8S_CLUSTER_ROUTER

    K8S_CLUSTER_LB_TCP = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "load_balancer",
                                   "external_ids:k8s-cluster-lb-tcp=yes")
    if not K8S_CLUSTER_LB_TCP:
        sys.exit("K8S_CLUSTER_LB_TCP not set")
    variables.K8S_CLUSTER_LB_TCP = K8S_CLUSTER_LB_TCP

    K8S_CLUSTER_LB_UDP = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "load_balancer",
                                   "external_ids:k8s-cluster-lb-udp=yes")
    if not K8S_CLUSTER_LB_UDP:
        sys.exit("K8S_CLUSTER_LB_UDP not set")
    variables.K8S_CLUSTER_LB_UDP = K8S_CLUSTER_LB_UDP

    variables.OVN_MODE = "overlay"
예제 #30
0
    def _get_ovn_external_ip_gateway(self):
        # XXX: In case of K8S 'external_ips', we can only expose it in one
        # gateway to prevent duplicate ARP responses.  We currently allocate
        # the first gateway to handle all 'external_ips'.
        try:
            physical_gateway = ovn_nbctl(
                "--data=bare", "--no-heading", "--columns=name", "find",
                "logical_router", "external_ids:first_gateway=yes").split()
            if not physical_gateway:
                return None
        except Exception as e:
            vlog.err("_get_ovn_external_ip_gateway: find failed %s" % (str(e)))

        return physical_gateway[0]
예제 #31
0
def ovn_init_overlay():
    if os.path.exists(UNIX_SOCKET):
        OVN_NB = "unix:%s" % UNIX_SOCKET
    else:
        sys.exit("OVN NB database does not have unix socket")
    variables.OVN_NB = OVN_NB

    K8S_API_SERVER = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".",
                               "external_ids:k8s-api-server").strip('"')
    if not K8S_API_SERVER:
        sys.exit("K8S_API_SERVER not set")
    if not K8S_API_SERVER.startswith("http"):
        variables.K8S_API_SERVER = "http://%s" % K8S_API_SERVER
    else:
        variables.K8S_API_SERVER = K8S_API_SERVER

    K8S_CLUSTER_ROUTER = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "logical_router",
                                   "external_ids:k8s-cluster-router=yes")
    if not K8S_CLUSTER_ROUTER:
        sys.exit("K8S_CLUSTER_ROUTER not set")
    variables.K8S_CLUSTER_ROUTER = K8S_CLUSTER_ROUTER

    K8S_CLUSTER_LB_TCP = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "load_balancer",
                                   "external_ids:k8s-cluster-lb-tcp=yes")
    if not K8S_CLUSTER_LB_TCP:
        sys.exit("K8S_CLUSTER_LB_TCP not set")
    variables.K8S_CLUSTER_LB_TCP = K8S_CLUSTER_LB_TCP

    K8S_CLUSTER_LB_UDP = ovn_nbctl("--data=bare", "--no-heading",
                                   "--columns=_uuid", "find", "load_balancer",
                                   "external_ids:k8s-cluster-lb-udp=yes")
    if not K8S_CLUSTER_LB_UDP:
        sys.exit("K8S_CLUSTER_LB_UDP not set")
    variables.K8S_CLUSTER_LB_UDP = K8S_CLUSTER_LB_UDP
예제 #32
0
    def _get_ovn_external_ip_gateway(self):
        # XXX: In case of K8S 'external_ips', we can only expose it in one
        # gateway to prevent duplicate ARP responses.  We currently allocate
        # the first gateway to handle all 'external_ips'.
        try:
            physical_gateway = ovn_nbctl(
                                "--data=bare", "--no-heading",
                                "--columns=name", "find",
                                "logical_router",
                                "external_ids:first_gateway=yes").split()
            if not physical_gateway:
                return None
        except Exception as e:
            vlog.err("_get_ovn_external_ip_gateway: find failed %s" % (str(e)))

        return physical_gateway[0]
예제 #33
0
    def _get_physical_gateway_ips(self):
        if self.physical_gateway_ips:
            return self.physical_gateway_ips

        try:
            physical_gateway_ip_networks = ovn_nbctl(
                "--data=bare", "--no-heading", "--columns=network", "find",
                "logical_router_port",
                "external_ids:gateway-physical-ip=yes").split()
        except Exception as e:
            vlog.err("_populate_gateway_ip: find failed %s" % (str(e)))

        for physical_gateway_ip_network in physical_gateway_ip_networks:
            (ip, mask) = physical_gateway_ip_network.split('/')
            self.physical_gateway_ips.append(ip)

        return self.physical_gateway_ips
예제 #34
0
    def _get_physical_gateway_ips(self):
        if self.physical_gateway_ips:
            return self.physical_gateway_ips

        try:
            physical_gateway_ip_networks = ovn_nbctl(
                                "--data=bare", "--no-heading",
                                "--columns=network", "find",
                                "logical_router_port",
                                "external_ids:gateway-physical-ip=yes").split()
        except Exception as e:
            vlog.err("_populate_gateway_ip: find failed %s" % (str(e)))

        for physical_gateway_ip_network in physical_gateway_ip_networks:
            ip, _mask = physical_gateway_ip_network.split('/')
            self.physical_gateway_ips.append(ip)

        return self.physical_gateway_ips
예제 #35
0
    def create_logical_port(self, event):
        data = event.metadata
        logical_switch = data['spec']['nodeName']
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not logical_switch or not pod_name:
            vlog.err("absent node name or pod name in pod %s. "
                     "Not creating logical port" % (data))
            return

        (gateway_ip, mask) = self._get_switch_gateway_ip(logical_switch)
        if not gateway_ip or not mask:
            vlog.err("_create_logical_port: failed to get gateway_ip")
            return

        try:
            ovn_nbctl("--wait=sb", "--", "--may-exist", "lsp-add",
                      logical_switch, logical_port, "--", "lsp-set-addresses",
                      logical_port, "dynamic", "--", "set",
                      "logical_switch_port", logical_port,
                      "external-ids:namespace=" + namespace,
                      "external-ids:pod=true")
        except Exception as e:
            vlog.err("_create_logical_port: lsp-add (%s)" % (str(e)))
            return

        try:
            ret = ovn_nbctl("get", "logical_switch_port", logical_port,
                            "dynamic_addresses")
            addresses = ast.literal_eval(ret)
        except Exception as e:
            vlog.err("_create_logical_port: get dynamic_addresses (%s)" %
                     (str(e)))

        if not len(addresses):
            vlog.err("_create_logical_port: failed to get dynamic address")
            return

        (mac_address, ip_address) = addresses.split()

        namespace = data['metadata']['namespace']
        pod_name = data['metadata']['name']

        ip_address_mask = "%s/%s" % (ip_address, mask)

        annotation = {
            'ip_address': ip_address_mask,
            'mac_address': mac_address,
            'gateway_ip': gateway_ip
        }

        try:
            kubernetes.set_pod_annotation(variables.K8S_API_SERVER, namespace,
                                          pod_name, "ovn", str(annotation))
        except Exception as e:
            vlog.err(
                "_create_logical_port: failed to annotate addresses (%s)" %
                (str(e)))
            return

        vlog.info("created logical port %s" % (logical_port))

        self._add_k8s_l4_port_name_cache(data, ip_address)
예제 #36
0
    def create_logical_port(self, event):
        data = event.metadata
        logical_switch = data['spec']['nodeName']
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not logical_switch or not pod_name:
            vlog.err("absent node name or pod name in pod %s. "
                     "Not creating logical port" % (data))
            return

        (gateway_ip, mask) = self._get_switch_gateway_ip(logical_switch)
        if not gateway_ip or not mask:
            vlog.err("_create_logical_port: failed to get gateway_ip")
            return

        try:
            ovn_nbctl("--wait=sb", "--", "--may-exist", "lsp-add",
                      logical_switch, logical_port, "--", "lsp-set-addresses",
                      logical_port, "dynamic", "--", "set",
                      "logical_switch_port", logical_port,
                      "external-ids:namespace=" + namespace,
                      "external-ids:pod=true")
        except Exception as e:
            vlog.err("_create_logical_port: lsp-add (%s)" % (str(e)))
            return

        try:
            ret = ovn_nbctl("get", "logical_switch_port", logical_port,
                            "dynamic_addresses")
            addresses = ast.literal_eval(ret)
        except Exception as e:
            vlog.err("_create_logical_port: get dynamic_addresses (%s)"
                     % (str(e)))

        if not len(addresses):
            vlog.err("_create_logical_port: failed to get dynamic address")
            return

        (mac_address, ip_address) = addresses.split()

        namespace = data['metadata']['namespace']
        pod_name = data['metadata']['name']

        ip_address_mask = "%s/%s" % (ip_address, mask)

        annotation = {'ip_address': str(ip_address_mask),
                      'mac_address': str(mac_address),
                      'gateway_ip': str(gateway_ip)}

        try:
            kubernetes.set_pod_annotation(variables.K8S_API_SERVER,
                                          namespace, pod_name,
                                          "ovn", json.dumps(annotation))
        except Exception as e:
            vlog.err("_create_logical_port: failed to annotate addresses (%s)"
                     % (str(e)))
            return

        vlog.info("created logical port %s" % (logical_port))

        self._add_k8s_l4_port_name_cache(data, ip_address)
예제 #37
0
    def create_logical_port(self, event):
        data = event.metadata
        logical_switch = data['spec']['nodeName']
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not logical_switch or not logical_port:
            vlog.err("absent node name or pod name in pod %s. "
                     "Not creating logical port" % (data))
            return

        (gateway_ip, mask) = self._get_switch_gateway_ip(logical_switch)
        if not gateway_ip or not mask:
            vlog.err("_create_logical_port: failed to get gateway_ip")
            return

        try:
            ovn_nbctl("--", "--if-exists", "lsp-del", logical_port, "--",
                      "lsp-add", logical_switch, logical_port, "--",
                      "lsp-set-addresses", logical_port, "dynamic")
        except Exception as e:
            vlog.err("_create_logical_port: lsp-add (%s)" % (str(e)))
            return

        # We wait for a maximum of 3 seconds to get the dynamic addresses in
        # intervals of 0.1 seconds.
        addresses = ""
        counter = 30
        while counter != 0:
            try:
                ret = ovn_nbctl("get", "logical_switch_port", logical_port,
                                "dynamic_addresses")
                addresses = ast.literal_eval(ret)
                if len(addresses):
                    break
            except Exception as e:
                vlog.err("_create_logical_port: get dynamic_addresses (%s)" %
                         (str(e)))

            time.sleep(0.1)
            counter = counter - 1

        if not len(addresses):
            vlog.err("_create_logical_port: failed to get addresses after "
                     "multiple retries.")
            return

        (mac_address, ip_address) = addresses.split()

        namespace = data['metadata']['namespace']
        pod_name = data['metadata']['name']

        ip_address_mask = "%s/%s" % (ip_address, mask)

        annotation = {
            'ip_address': ip_address_mask,
            'mac_address': mac_address,
            'gateway_ip': gateway_ip
        }

        try:
            kubernetes.set_pod_annotation(variables.K8S_API_SERVER, namespace,
                                          pod_name, "ovn", str(annotation))
        except Exception as e:
            vlog.err(
                "_create_logical_port: failed to annotate addresses (%s)" %
                (str(e)))
            return

        vlog.info("created logical port %s" % (logical_port))
예제 #38
0
    def sync_services(self, services):
        # For all the services, we will populate the below lists with
        # IP:port that act as VIP in the OVN load-balancers.
        tcp_nodeport_services = []
        udp_nodeport_services = []
        tcp_services = []
        udp_services = []
        services = services.get('items', [])
        for service in services:
            service_type = service['spec'].get('type')
            if service_type != "ClusterIP" and service_type != "NodePort":
                continue

            service_ip = service['spec'].get('clusterIP')
            if not service_ip:
                continue

            service_ports = service['spec'].get('ports')
            if not service_ports:
                continue

            external_ips = service['spec'].get('externalIPs')

            for service_port in service_ports:
                if service_type == "NodePort":
                    port = service_port.get('nodePort')
                else:
                    port = service_port.get('port')

                if not port:
                    continue

                protocol = service_port.get('protocol', 'TCP')

                if service_type == "NodePort":
                    physical_gateway_ips = self._get_physical_gateway_ips()
                    for gateway_ip in physical_gateway_ips:
                        key = "%s:%s" % (gateway_ip, port)
                        if protocol == "TCP":
                            tcp_nodeport_services.append(key)
                        else:
                            udp_nodeport_services.append(key)
                elif service_type == "ClusterIP":
                    key = "%s:%s" % (service_ip, port)
                    if protocol == "TCP":
                        tcp_services.append(key)
                    else:
                        udp_services.append(key)

                if external_ips:
                    for external_ip in external_ips:
                        key = "%s:%s" % (external_ip, port)
                        if protocol == "TCP":
                            tcp_nodeport_services.append(key)
                        else:
                            udp_nodeport_services.append(key)

        # For each of the OVN load-balancer, if the VIP that exists in
        # the load balancer is not seen in current k8s services, we
        # delete it.
        load_balancers = {variables.K8S_CLUSTER_LB_TCP: tcp_services,
                          variables.K8S_CLUSTER_LB_UDP: udp_services,
                          variables.K8S_NS_LB_TCP: tcp_nodeport_services,
                          variables.K8S_NS_LB_UDP: udp_nodeport_services}

        for load_balancer, k8s_services in load_balancers.items():
            vips = self._get_load_balancer_vips(load_balancer)
            if not vips:
                continue

            for vip in vips:
                if vip not in k8s_services:
                    vip = "\"" + vip + "\""
                    try:
                        ovn_nbctl("remove", "load_balancer", load_balancer,
                                  "vips", vip)
                        vlog.info("sync_services: deleted vip %s from %s"
                                  % (vip, load_balancer))
                    except Exception as e:
                        vlog.err("sync_services: failed to remove vip %s"
                                 "from %s (%s)" % (vip, load_balancer, str(e)))
예제 #39
0
    def sync_services(self, services):
        # For all the 'clusterIP' services, we will populate the below lists
        # (inside dict) with IP:port.
        cluster_services = {'TCP': [], 'UDP': []}

        # For all the NodePort services, we will populate the below lists with
        # just nodeport or 'external_ip:port'.
        nodeport_services = {'TCP': [], 'UDP': []}

        services = services.get('items', [])
        for service in services:
            service_type = service['spec'].get('type')
            if service_type != "ClusterIP" and service_type != "NodePort":
                continue

            service_ip = service['spec'].get('clusterIP')
            if not service_ip:
                continue

            service_ports = service['spec'].get('ports')
            if not service_ports:
                continue

            external_ips = service['spec'].get('externalIPs')

            for service_port in service_ports:
                if service_type == "NodePort":
                    port = service_port.get('nodePort')
                else:
                    port = service_port.get('port')

                if not port:
                    continue

                protocol = service_port.get('protocol', 'TCP')

                if service_type == "NodePort":
                    if protocol == "TCP":
                        nodeport_services['TCP'].append(str(port))
                    else:
                        nodeport_services['UDP'].append(str(port))
                elif service_type == "ClusterIP":
                    key = "%s:%s" % (service_ip, port)
                    if protocol == "TCP":
                        cluster_services['TCP'].append(key)
                    else:
                        cluster_services['UDP'].append(key)

                if external_ips:
                    for external_ip in external_ips:
                        key = "%s:%s" % (external_ip, port)
                        if protocol == "TCP":
                            nodeport_services['TCP'].append(key)
                        else:
                            nodeport_services['UDP'].append(key)

        # For OVN cluster load-balancer if the VIP that exists in the
        # OVN load balancer is not seen in current k8s services, we delete it.
        load_balancers = {
                         variables.K8S_CLUSTER_LB_TCP: cluster_services['TCP'],
                         variables.K8S_CLUSTER_LB_UDP: cluster_services['UDP'],
                         }

        for load_balancer, k8s_services in load_balancers.items():
            vips = self._get_load_balancer_vips(load_balancer)
            if not vips:
                continue

            for vip in vips:
                if vip not in k8s_services:
                    vip = "\"" + vip + "\""
                    self._delete_load_balancer_vip(load_balancer, vip)

        # For each gateway, remove any VIP that does not exist in
        # 'nodeport_services'
        physical_gateways = self._get_ovn_gateways()
        for physical_gateway in physical_gateways:
            for protocol, service in nodeport_services.items():
                try:
                    external_id_key = protocol + "_lb_gateway_router"
                    load_balancer = ovn_nbctl(
                                    "--data=bare", "--no-heading",
                                    "--columns=_uuid", "find", "load_balancer",
                                    "external_ids:" + external_id_key + "=" +
                                    physical_gateway
                                    ).strip('"')
                except Exception as e:
                    vlog.err("sync_services: get failed for"
                             " %s (%s)" % (physical_gateway, str(e)))
                    continue

                if not load_balancer:
                    continue

                # Get the OVN load-balancer VIPs.
                vips = self._get_load_balancer_vips(load_balancer)
                if not vips:
                    continue

                for vip in vips:
                    vip_and_port = vip.split(":")
                    if len(vip_and_port) == 1:
                        # In a OVN load-balancer, we should always have
                        # vip:port.  In the unlikely event that it is not
                        # the case, skip it.
                        continue

                    # An example 'service' is ["3892", "10.1.1.20:8880"]
                    if vip_and_port[1] in service or vip in service:
                        continue

                    vip = "\"" + vip + "\""
                    self._delete_load_balancer_vip(load_balancer, vip)
예제 #40
0
    def sync_services(self, services):
        # For all the services, we will populate the below lists with
        # IP:port that act as VIP in the OVN load-balancers.
        tcp_nodeport_services = []
        udp_nodeport_services = []
        tcp_services = []
        udp_services = []
        services = services.get('items', [])
        for service in services:
            service_type = service['spec'].get('type')
            if service_type != "ClusterIP" and service_type != "NodePort":
                continue

            service_ip = service['spec'].get('clusterIP')
            if not service_ip:
                continue

            service_ports = service['spec'].get('ports')
            if not service_ports:
                continue

            external_ips = service['spec'].get('externalIPs')

            for service_port in service_ports:
                if service_type == "NodePort":
                    port = service_port.get('nodePort')
                else:
                    port = service_port.get('port')

                if not port:
                    continue

                protocol = service_port.get('protocol', 'TCP')

                if service_type == "NodePort":
                    physical_gateway_ips = self._get_physical_gateway_ips()
                    for gateway_ip in physical_gateway_ips:
                        key = "%s:%s" % (gateway_ip, port)
                        if protocol == "TCP":
                            tcp_nodeport_services.append(key)
                        else:
                            udp_nodeport_services.append(key)
                elif service_type == "ClusterIP":
                    key = "%s:%s" % (service_ip, port)
                    if protocol == "TCP":
                        tcp_services.append(key)
                    else:
                        udp_services.append(key)

                if external_ips:
                    for external_ip in external_ips:
                        key = "%s:%s" % (external_ip, port)
                        if protocol == "TCP":
                            tcp_nodeport_services.append(key)
                        else:
                            udp_nodeport_services.append(key)

        # For each of the OVN load-balancer, if the VIP that exists in
        # the load balancer is not seen in current k8s services, we
        # delete it.
        load_balancers = {
            variables.K8S_CLUSTER_LB_TCP: tcp_services,
            variables.K8S_CLUSTER_LB_UDP: udp_services,
            variables.K8S_NS_LB_TCP: tcp_nodeport_services,
            variables.K8S_NS_LB_UDP: udp_nodeport_services
        }

        for load_balancer, k8s_services in load_balancers.items():
            vips = self._get_load_balancer_vips(load_balancer)
            if not vips:
                continue

            for vip in vips:
                if vip not in k8s_services:
                    vip = "\"" + vip + "\""
                    try:
                        ovn_nbctl("remove", "load_balancer", load_balancer,
                                  "vips", vip)
                        vlog.info("sync_services: deleted vip %s from %s" %
                                  (vip, load_balancer))
                    except Exception as e:
                        vlog.err("sync_services: failed to remove vip %s"
                                 "from %s (%s)" % (vip, load_balancer, str(e)))
예제 #41
0
    def sync_services(self, services):
        # For all the 'clusterIP' services, we will populate the below lists
        # (inside dict) with IP:port.
        cluster_services = {'TCP': [], 'UDP': []}

        # For all the NodePort services, we will populate the below lists with
        # just nodeport or 'external_ip:port'.
        nodeport_services = {'TCP': [], 'UDP': []}

        services = services.get('items', [])
        for service in services:
            service_type = service['spec'].get('type')
            if service_type != "ClusterIP" and service_type != "NodePort":
                continue

            service_ip = service['spec'].get('clusterIP')
            if not service_ip:
                continue

            service_ports = service['spec'].get('ports')
            if not service_ports:
                continue

            external_ips = service['spec'].get('externalIPs')

            for service_port in service_ports:
                if service_type == "NodePort":
                    port = service_port.get('nodePort')
                else:
                    port = service_port.get('port')

                if not port:
                    continue

                protocol = service_port.get('protocol', 'TCP')

                if service_type == "NodePort":
                    if protocol == "TCP":
                        nodeport_services['TCP'].append(str(port))
                    else:
                        nodeport_services['UDP'].append(str(port))
                elif service_type == "ClusterIP":
                    key = "%s:%s" % (service_ip, port)
                    if protocol == "TCP":
                        cluster_services['TCP'].append(key)
                    else:
                        cluster_services['UDP'].append(key)

                if external_ips:
                    for external_ip in external_ips:
                        key = "%s:%s" % (external_ip, port)
                        if protocol == "TCP":
                            nodeport_services['TCP'].append(key)
                        else:
                            nodeport_services['UDP'].append(key)

        # For OVN cluster load-balancer if the VIP that exists in the
        # OVN load balancer is not seen in current k8s services, we delete it.
        load_balancers = {
            variables.K8S_CLUSTER_LB_TCP: cluster_services['TCP'],
            variables.K8S_CLUSTER_LB_UDP: cluster_services['UDP'],
        }

        for load_balancer, k8s_services in load_balancers.items():
            vips = self._get_load_balancer_vips(load_balancer)
            if not vips:
                continue

            for vip in vips:
                if vip not in k8s_services:
                    vip = "\"" + vip + "\""
                    self._delete_load_balancer_vip(load_balancer, vip)

        # For each gateway, remove any VIP that does not exist in
        # 'nodeport_services'
        physical_gateways = self._get_ovn_gateways()
        for physical_gateway in physical_gateways:
            for protocol, service in nodeport_services.items():
                try:
                    external_id_key = protocol + "_lb_gateway_router"
                    load_balancer = ovn_nbctl(
                        "--data=bare", "--no-heading", "--columns=_uuid",
                        "find", "load_balancer", "external_ids:" +
                        external_id_key + "=" + physical_gateway).strip('"')
                except Exception as e:
                    vlog.err("sync_services: get failed for"
                             " %s (%s)" % (physical_gateway, str(e)))
                    continue

                if not load_balancer:
                    continue

                # Get the OVN load-balancer VIPs.
                vips = self._get_load_balancer_vips(load_balancer)
                if not vips:
                    continue

                for vip in vips:
                    vip_and_port = vip.split(":")
                    if len(vip_and_port) == 1:
                        # In a OVN load-balancer, we should always have
                        # vip:port.  In the unlikely event that it is not
                        # the case, skip it.
                        continue

                    # An example 'service' is ["3892", "10.1.1.20:8880"]
                    if vip_and_port[1] in service or vip in service:
                        continue

                    vip = "\"" + vip + "\""
                    self._delete_load_balancer_vip(load_balancer, vip)
예제 #42
0
    def create_logical_port(self, event):
        data = event.metadata
        logical_switch = data['spec']['nodeName']
        pod_name = data['metadata']['name']
        namespace = data['metadata']['namespace']
        logical_port = "%s_%s" % (namespace, pod_name)
        if not logical_switch or not pod_name:
            vlog.err("absent node name or pod name in pod %s. "
                     "Not creating logical port" % (data))
            return

        (gateway_ip, mask) = self._get_switch_gateway_ip(logical_switch)
        if not gateway_ip or not mask:
            vlog.err("_create_logical_port: failed to get gateway_ip")
            return

        try:
            ovn_nbctl("--", "--may-exist", "lsp-add", logical_switch,
                      logical_port, "--", "lsp-set-addresses",
                      logical_port, "dynamic", "--", "set",
                      "logical_switch_port", logical_port,
                      "external-ids:namespace=" + namespace,
                      "external-ids:pod=true")
        except Exception as e:
            vlog.err("_create_logical_port: lsp-add (%s)" % (str(e)))
            return

        # We wait for a maximum of 3 seconds to get the dynamic addresses in
        # intervals of 0.1 seconds.
        addresses = ""
        counter = 30
        while counter != 0:
            try:
                ret = ovn_nbctl("get", "logical_switch_port", logical_port,
                                "dynamic_addresses")
                addresses = ast.literal_eval(ret)
                if len(addresses):
                    break
            except Exception as e:
                vlog.err("_create_logical_port: get dynamic_addresses (%s)"
                         % (str(e)))

            time.sleep(0.1)
            counter = counter - 1

        if not len(addresses):
            vlog.err("_create_logical_port: failed to get addresses after "
                     "multiple retries.")
            return

        (mac_address, ip_address) = addresses.split()

        namespace = data['metadata']['namespace']
        pod_name = data['metadata']['name']

        ip_address_mask = "%s/%s" % (ip_address, mask)

        annotation = {'ip_address': ip_address_mask,
                      'mac_address': mac_address,
                      'gateway_ip': gateway_ip}

        try:
            kubernetes.set_pod_annotation(variables.K8S_API_SERVER,
                                          namespace, pod_name,
                                          "ovn", str(annotation))
        except Exception as e:
            vlog.err("_create_logical_port: failed to annotate addresses (%s)"
                     % (str(e)))
            return

        vlog.info("created logical port %s" % (logical_port))