Example #1
0
def find_random_available_port() -> int:
    for port in random.sample(range(START_PORT, END_PORT),
                              k=MAX_NUMBER_OF_TRIES):
        if check_port_availability(port):
            tunnel_port = port
            break
    else:
        error_msg = Texts.NO_AVAILABLE_PORT_ERROR_MSG
        logger.error(error_msg)
        raise LocalPortOccupiedError(error_msg)

    return tunnel_port
Example #2
0
def test_check_port_availability_occupied(mocker):
    socket_local = mocker.patch("socket.socket.bind")
    socket_local.side_effect = OSError(errno.EADDRINUSE, "Address in use")

    assert not check_port_availability(9000)
Example #3
0
def test_check_port_availability_failure(mocker):
    socket_local = mocker.patch("socket.socket.bind")
    socket_local.side_effect = OSError()

    with pytest.raises(RuntimeError):
        check_port_availability(9000)
Example #4
0
def test_check_port_availability_success(mocker):
    mocker.patch("socket.socket")
    assert check_port_availability(9000)
Example #5
0
def start_port_forwarding(
        k8s_app_name: NAUTAAppNames,
        port: int = None,
        app_name: str = None,
        number_of_retries: int = 0,
        namespace: str = None) -> Tuple[subprocess.Popen, int, int]:
    """
    Creates a proxy responsible for forwarding requests to and from a
    kubernetes' local docker proxy. In case of any errors during creating the
    process - throws a RuntimeError exception with a short description of
    a cause of a problem.
    When proxy created by this function is no longer needed - it should
    be closed by calling kill() function on a process returned by this
    function.

    :param k8s_app_name: name of kubernetes application for tunnel creation
                         value taken from NAUTAAppNames enum
    :param port: if given - the system will try to use it as a local port. Random port will be used
     if that port is not available
    :return:
        instance of a process with proxy, tunneled port and container port
    """
    logger.debug("Start port forwarding")

    try:
        service_node_port = None
        service_container_port = None

        app_services = get_app_services(nauta_app_name=k8s_app_name,
                                        namespace=namespace,
                                        app_name=app_name)

        if app_services:
            service_node_port = app_services[0].spec.ports[0].node_port
            if service_node_port:
                logger.debug('Service node port pod has been found: {}'.format(
                    service_node_port))

            service_container_port = app_services[0].spec.ports[0].port
            if service_container_port:
                logger.debug(
                    'Service container port has been found: {}'.format(
                        service_container_port))
            service_name = app_services[0].metadata.name
            namespace = app_services[0].metadata.namespace

        if not service_node_port and not service_container_port:
            logger.error(f'Cannot find open ports for {k8s_app_name} app')
            raise KubernetesError(Texts.PROXY_CREATION_MISSING_PORT_ERROR_MSG)

        if port and check_port_availability(port):
            tunnel_port = port
        else:
            tunnel_port = find_random_available_port()

        port_forward_command = [
            'kubectl', 'port-forward', f'--namespace={namespace}',
            f'service/{service_name}',
            f'{tunnel_port}:{service_container_port}', '-v=4'
        ]

        logger.debug(port_forward_command)

        process = None
        if number_of_retries:
            for i in range(number_of_retries - 1):
                try:
                    process = system.execute_subprocess_command(
                        port_forward_command)
                except Exception:
                    logger.exception(
                        "Error during setting up proxy - retrying.")
                else:
                    break
                time.sleep(5)

        if not process:
            process = system.execute_subprocess_command(port_forward_command)

    except KubernetesError as exe:
        raise RuntimeError(exe)
    except LocalPortOccupiedError as exe:
        raise exe
    except Exception:
        raise RuntimeError(Texts.PROXY_CREATION_OTHER_ERROR_MSG)

    logger.info("Port forwarding - proxy set up")
    return process, tunnel_port, service_container_port