Ejemplo n.º 1
0
def handle(handle_code: customer_code.Function, port: int = 5000):
    """
    FDK entry point
    :param handle_code: customer's code
    :type handle_code: fdk.customer_code.Function
    :param port: TCP port to start an FDK at
    :type port: int
    :return: None
    """
    host = "localhost"
    log.log("entering handle")

    log.log("Starting HTTP server on "
            "TCP socket: {0}:{1}".format(host, port))
    loop = asyncio.get_event_loop()

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(("localhost", port))

    rtr = router.Router()
    rtr.add("/call", frozenset({"POST"}),
            event_handler.event_handle(handle_code))
    srv = app.AsyncHTTPServer(name="fdk-tcp-debug", router=rtr)
    start_serving, server_forever = srv.run(sock=sock, loop=loop)
    start_serving()
    server_forever()
Ejemplo n.º 2
0
    def SetResponseHeaders(self, headers, status_code):
        log.log("setting headers. gateway: {0}".format(self.__is_gateway()))
        if self.__is_gateway():
            headers = hs.encap_headers(headers, status=status_code)

        for k, v in headers.items():
            self.__response_headers[k.lower()] = v
Ejemplo n.º 3
0
def setup_unix_server(handle_func, loop=None):
    log.log("in setup_unix_server")
    app = web.Application(loop=loop)

    app.router.add_post('/{tail:.*}', handle(handle_func))

    return app
Ejemplo n.º 4
0
async def handle_request(handler_code, format_def, **kwargs):
    """
    Handles a function's request
    :param handler_code: customer's code
    :type handler_code: fdk.customer_code.Function
    :param format_def: function's format
    :type format_def: str
    :param kwargs: request-specific parameters
    :type kwargs: dict
    :return: function's response
    :rtype: fdk.response.Response
    """
    log.log("in handle_request")
    ctx, body = context.context_from_format(format_def, **kwargs)
    log.log("context provisioned")
    try:
        response_data = await with_deadline(ctx, handler_code, body)
        log.log("function result obtained")
        if isinstance(response_data, response.Response):
            return response_data

        headers = ctx.GetResponseHeaders()
        log.log("response headers obtained")
        return response.Response(ctx,
                                 response_data=response_data,
                                 headers=headers,
                                 status_code=200)

    except (Exception, TimeoutError) as ex:
        log.log("exception appeared: {0}".format(ex))
        traceback.print_exc(file=sys.stderr)
        return errors.DispatchException(ctx, 502, str(ex)).response()
Ejemplo n.º 5
0
    def __init__(self, app_id, app_name, fn_id, fn_name, call_id,
                 content_type="application/octet-stream",
                 deadline=None, config=None,
                 headers=None, request_url=None,
                 method="POST", fn_format=None,
                 tracing_context=None):
        """
        Request context here to be a placeholder
        for request-specific attributes
        :param app_id: Fn App ID
        :type app_id: str
        :param app_name: Fn App name
        :type app_name: str
        :param fn_id: Fn App Fn ID
        :type fn_id: str
        :param fn_name: Fn name
        :type fn_name: str
        :param call_id: Fn call ID
        :type call_id: str
        :param content_type: request content type
        :type content_type: str
        :param deadline: request deadline
        :type deadline: str
        :param config: an app/fn config
        :type config: dict
        :param headers: request headers
        :type headers: dict
        :param request_url: request URL
        :type request_url: str
        :param method: request method
        :type method: str
        :param fn_format: function format
        :type fn_format: str
        :param tracing_context: tracing context
        :type tracing_context: TracingContext
        """
        self.__app_id = app_id
        self.__fn_id = fn_id
        self.__call_id = call_id
        self.__config = config if config else {}
        self.__headers = headers if headers else {}
        self.__http_headers = {}
        self.__deadline = deadline
        self.__content_type = content_type
        self._request_url = request_url
        self._method = method
        self.__response_headers = {}
        self.__fn_format = fn_format
        self.__app_name = app_name
        self.__fn_name = fn_name
        self.__tracing_context = tracing_context if tracing_context else None

        log.log("request headers. gateway: {0} {1}"
                .format(self.__is_gateway(), headers))

        if self.__is_gateway():
            self.__headers = hs.decap_headers(headers, True)
            self.__http_headers = hs.decap_headers(headers, False)
Ejemplo n.º 6
0
def serialize_response_data(data, content_type):
    log.log("in serialize_response_data")
    if data:
        if "application/json" in content_type:
            return bytes(ujson.dumps(data), "utf8")
        if "text/plain" in content_type:
            return bytes(str(data), "utf8")
        if "application/xml" in content_type:
            # returns a bytearray
            if isinstance(data, str):
                return bytes(data, "utf8")
            return ElementTree.tostring(data, encoding='utf8', method='xml')
        if "application/octet-stream" in content_type:
            return data
    return
Ejemplo n.º 7
0
def handle(handle_func):
    log.log("entering handle")
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    loop = asyncio.get_event_loop()

    format_def = os.environ.get(constants.FN_FORMAT)
    lsnr = os.environ.get(constants.FN_LISTENER)
    log.log("format: {0}".format(format_def))

    if format_def == constants.HTTPSTREAM:
        if lsnr is None:
            log.log("{0} is not set".format(constants.FN_LISTENER))
            sys.exit(1)
        log.log("{0} is set, value: {1}".format(constants.FN_LISTENER, lsnr))
        http_stream.start(handle_func, lsnr, loop=loop)
    else:
        log.log("incompatible function format!")
        print("incompatible function format!", file=sys.stderr, flush=True)
        sys.exit("incompatible function format!")
Ejemplo n.º 8
0
async def handle_request(handle_func, format_def, **kwargs):

    ctx, body = context.context_from_format(format_def, **kwargs)

    try:
        response_data = await with_deadline(ctx, handle_func, body)

        if isinstance(response_data, response.RawResponse):
            return response_data

        resp_class = response.response_class_from_context(ctx)
        return resp_class(
            ctx, response_data=response_data, headers={}, status_code=200)

    except (Exception, TimeoutError) as ex:
        log.log("exception appeared")
        traceback.print_exc(file=sys.stderr)
        status = 502 if isinstance(ex, TimeoutError) else 500
        err_class = errors.error_class_from_format(format_def)
        return err_class(ctx, status, str(ex), ).response()
Ejemplo n.º 9
0
    async def pure_handler(request):
        log.log("in pure_handler")
        data = None
        if request.has_body:
            log.log("has body: {}".format(request.has_body))
            log.log("request comes with data")
            data = await request.content.read()
        response = await runner.handle_request(
            handle_func, constants.HTTPSTREAM,
            request=request, data=data)
        log.log("request execution completed")
        headers = response.context().GetResponseHeaders()

        response_content_type = headers.get(
            constants.CONTENT_TYPE, "application/json"
        )
        headers.set(constants.CONTENT_TYPE, response_content_type)
        kwargs = {
            "headers": headers.http_raw()
        }

        sdata = serialize_response_data(
            response.body(), response_content_type)

        if response.status() >= 500:
            kwargs.update(reason=sdata, status=500)
        else:
            kwargs.update(body=sdata, status=200)

        log.log("sending response back")
        try:
            resp = web.Response(**kwargs)
        except (Exception, BaseException) as ex:

            resp = web.Response(
                text=str(ex), reason=str(ex),
                status=500, content_type="text/plain", headers={
                    "Fn-Http-Status": str(500)
                })

        return resp
Ejemplo n.º 10
0
def handle(handle_code: customer_code.Function):
    """
    FDK entry point
    :param handle_code: customer's code
    :type handle_code: fdk.customer_code.Function
    :return: None
    """
    log.log("entering handle")
    if not isinstance(handle_code, customer_code.Function):
        sys.exit(
            '\n\n\nWARNING!\n\n'
            'Your code is not compatible the the latest FDK!\n\n'
            'Update Dockerfile entry point to:\n'
            'ENTRYPOINT["/python/bin/fdk", "<path-to-your-func.py>", {0}]\n\n'
            'if __name__ == "__main__":\n\tfdk.handle(handler)\n\n'
            'syntax no longer supported!\n'
            'Update your code as soon as possible!'
            '\n\n\n'.format(handle_code.__name__))

    loop = asyncio.get_event_loop()

    format_def = os.environ.get(constants.FN_FORMAT)
    lsnr = os.environ.get(constants.FN_LISTENER)
    log.log("{0} is set, value: {1}".format(constants.FN_FORMAT, format_def))

    if lsnr is None:
        sys.exit("{0} is not set".format(constants.FN_LISTENER))

    log.log("{0} is set, value: {1}".format(constants.FN_LISTENER, lsnr))

    if format_def == constants.HTTPSTREAM:
        start(handle_code, lsnr, loop=loop)
    else:
        sys.exit("incompatible function format!")
Ejemplo n.º 11
0
    async def pure_handler(request):
        from fdk import runner
        log.log("in pure_handler")
        headers = dict(request.headers)
        log_frame_header(headers)
        func_response = await runner.handle_request(handle_code,
                                                    constants.HTTPSTREAM,
                                                    headers=headers,
                                                    data=io.BytesIO(
                                                        request.body))
        log.log("request execution completed")

        headers = func_response.context().GetResponseHeaders()
        status = func_response.status()
        if status not in constants.FN_ENFORCED_RESPONSE_CODES:
            status = constants.FN_DEFAULT_RESPONSE_CODE

        return response.HTTPResponse(
            headers=headers,
            status=status,
            content_type=headers.get(constants.CONTENT_TYPE),
            body_bytes=func_response.body_bytes(),
        )
Ejemplo n.º 12
0
async def handle_request(handler_code, format_def, **kwargs):
    """
    Handles a function's request
    :param handler_code: customer's code
    :type handler_code: fdk.customer_code.Function
    :param format_def: function's format
    :type format_def: str
    :param kwargs: request-specific parameters
    :type kwargs: dict
    :return: function's response
    :rtype: fdk.response.Response
    """
    log.log("in handle_request")
    ctx, body = context.context_from_format(format_def, **kwargs)
    log.set_request_id(ctx.CallID())
    log.log("context provisioned")
    try:
        response_data = await with_deadline(ctx, handler_code, body)
        log.log("function result obtained")
        if isinstance(response_data, response.Response):
            return response_data

        headers = ctx.GetResponseHeaders()
        log.log("response headers obtained")
        return response.Response(ctx,
                                 response_data=response_data,
                                 headers=headers,
                                 status_code=200)

    except (Exception, TimeoutError) as ex:
        log.log("exception appeared: {0}".format(ex))
        (exctype, value, tb) = sys.exc_info()
        tb_flat = ''.join(
            s.replace('\n', '\\n') for s in traceback.format_tb(tb))
        log.get_request_log().error('{}:{}'.format(value, tb_flat))
        return errors.DispatchException(ctx, 502, str(ex)).response()
Ejemplo n.º 13
0
def start(handle_code: customer_code.Function,
          uds: str,
          loop: asyncio.AbstractEventLoop = None):
    """
    Unix domain socket HTTP server entry point
    :param handle_code: customer's code
    :type handle_code: fdk.customer_code.Function
    :param uds: path to a Unix domain socket
    :type uds: str
    :param loop: event loop
    :type loop: asyncio.AbstractEventLoop
    :return: None
    """
    log.log("in http_stream.start")
    socket_path = os.path.normpath(str(uds).lstrip("unix:"))
    socket_dir, socket_file = os.path.split(socket_path)
    if socket_file == "":
        sys.exit("malformed FN_LISTENER env var "
                 "value: {0}".format(socket_path))

    phony_socket_path = os.path.join(socket_dir, "phony" + socket_file)

    log.log("deleting socket files if they exist")
    try:
        os.remove(socket_path)
        os.remove(phony_socket_path)
    except OSError:
        pass

    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.bind(phony_socket_path)

    rtr = router.Router()
    rtr.add("/call", frozenset({"POST"}),
            event_handler.event_handle(handle_code))

    srv = app.AsyncHTTPServer(name="fdk", router=rtr)
    start_serving, server_forever = srv.run(sock=sock, loop=loop)

    try:
        log.log("CHMOD 666 {0}".format(phony_socket_path))
        os.chmod(phony_socket_path, 0o666)
        log.log("phony socket permissions: {0}".format(
            oct(os.stat(phony_socket_path).st_mode)))
        log.log("calling '.start_serving()'")
        start_serving()
        log.log("sym-linking {0} to {1}".format(socket_path,
                                                phony_socket_path))
        os.symlink(os.path.basename(phony_socket_path), socket_path)
        log.log("socket permissions: {0}".format(
            oct(os.stat(socket_path).st_mode)))
        log.log("starting infinite loop")

    except (Exception, BaseException) as ex:
        log.log(str(ex))
        raise ex

    server_forever()
Ejemplo n.º 14
0
def start(handle_func, uds, loop=None):
    log.log("in http_stream.start")
    app = setup_unix_server(handle_func, loop=loop)

    socket_path = str(uds).lstrip("unix:")

    if asyncio.iscoroutine(app):
        app = loop.run_until_complete(app)

    log.log("socket file exist? - {0}"
            .format(os.path.exists(socket_path)))
    app_runner = web.AppRunner(
        app, handle_signals=True,
        access_log=log.get_logger())

    # setting up app runner
    log.log("setting app_runner")
    loop.run_until_complete(app_runner.setup())

    # try to remove pre-existing UDS: ignore errors here
    socket_dir, socket_file = os.path.split(socket_path)
    phony_socket_path = os.path.join(
        socket_dir, "phony" + socket_file)

    log.log("deleting socket files if they exist")
    try:
        os.remove(socket_path)
        os.remove(phony_socket_path)
    except (FileNotFoundError, Exception, BaseException):
        pass

    log.log("starting unix socket site")
    uds_sock = web.UnixSite(
        app_runner, phony_socket_path,
        shutdown_timeout=0.1)
    loop.run_until_complete(uds_sock.start())
    try:

        try:
            log.log("CHMOD 666 {0}".format(phony_socket_path))
            os.chmod(phony_socket_path, 0o666)
            log.log("phony socket permissions: {0}"
                    .format(oct(os.stat(phony_socket_path).st_mode)))
            log.log("sym-linking {0} to {1}".format(
                socket_path, phony_socket_path))
            os.symlink(os.path.basename(phony_socket_path), socket_path)
            log.log("socket permissions: {0}"
                    .format(oct(os.stat(socket_path).st_mode)))
        except (Exception, BaseException) as ex:
            log.log(str(ex))
            raise ex
        try:
            log.log("starting infinite loop")
            loop.run_forever()
        except web.GracefulExit:
            pass
    finally:
        loop.run_until_complete(app_runner.cleanup())
    if hasattr(loop, 'shutdown_asyncgens'):
        loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()