diff --git a/template/python3-flask-debian/Dockerfile b/template/python3-flask-debian/Dockerfile new file mode 100644 index 0000000..048b637 --- /dev/null +++ b/template/python3-flask-debian/Dockerfile @@ -0,0 +1,56 @@ +FROM openfaas/of-watchdog:0.7.2 as watchdog +FROM python:3.7-slim-buster + +COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog +RUN chmod +x /usr/bin/fwatchdog + +ARG ADDITIONAL_PACKAGE +# Alternatively use ADD https:// (which will not be cached by Docker builder) + +RUN apt-get -qy update && apt-get -qy install gcc make ${ADDITIONAL_PACKAGE} + +# Add non root user +RUN addgroup --system app && adduser app --system --ingroup app +RUN chown app /home/app + +USER app + +ENV PATH=$PATH:/home/app/.local/bin + +WORKDIR /home/app/ + +COPY index.py . +COPY requirements.txt . + +USER root +RUN pip install -r requirements.txt + +#build function directory and install user specified componenets. +USER app + +RUN mkdir -p function +RUN touch ./function/__init__.py +WORKDIR /home/app/function/ +COPY function/requirements.txt . +RUN pip install --user -r requirements.txt + +WORKDIR /home/app/ + +#install function code +USER root + +COPY function function +RUN chown -R app:app ./ + +#configure WSGI server and healthcheck +USER app + +ENV fprocess="python index.py" + +ENV cgi_headers="true" +ENV mode="http" +ENV upstream_url="http://127.0.0.1:5000" + +HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1 + +CMD ["fwatchdog"] diff --git a/template/python3-flask-debian/function/__init__.py b/template/python3-flask-debian/function/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/template/python3-flask-debian/function/handler.py b/template/python3-flask-debian/function/handler.py new file mode 100644 index 0000000..a7098fa --- /dev/null +++ b/template/python3-flask-debian/function/handler.py @@ -0,0 +1,7 @@ +def handle(req): + """handle a request to the function + Args: + req (str): request body + """ + + return req diff --git a/template/python3-flask-debian/function/requirements.txt b/template/python3-flask-debian/function/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/template/python3-flask-debian/index.py b/template/python3-flask-debian/index.py new file mode 100644 index 0000000..62d1379 --- /dev/null +++ b/template/python3-flask-debian/index.py @@ -0,0 +1,32 @@ +# Copyright (c) Alex Ellis 2017. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + +from flask import Flask, request +from function import handler +#from gevent.wsgi import WSGIServer +from gevent.pywsgi import WSGIServer + +app = Flask(__name__) + +@app.before_request +def fix_transfer_encoding(): + """ + Sets the "wsgi.input_terminated" environment flag, thus enabling + Werkzeug to pass chunked requests as streams. The gunicorn server + should set this, but it's not yet been implemented. + """ + + transfer_encoding = request.headers.get("Transfer-Encoding", None) + if transfer_encoding == u"chunked": + request.environ["wsgi.input_terminated"] = True + +@app.route("/", defaults={"path": ""}, methods=["POST", "GET"]) +@app.route("/", methods=["POST", "GET"]) +def main_route(path): + ret = handler.handle(request.get_data()) + return ret + +if __name__ == '__main__': + + http_server = WSGIServer(('0.0.0.0', 5000), app) + http_server.serve_forever() diff --git a/template/python3-flask-debian/requirements.txt b/template/python3-flask-debian/requirements.txt new file mode 100644 index 0000000..4c0baf0 --- /dev/null +++ b/template/python3-flask-debian/requirements.txt @@ -0,0 +1,3 @@ +flask +gevent + diff --git a/template/python3-flask-debian/template.yml b/template/python3-flask-debian/template.yml new file mode 100644 index 0000000..4bbcb1b --- /dev/null +++ b/template/python3-flask-debian/template.yml @@ -0,0 +1,2 @@ +language: python3-flask-debian +fprocess: python index.py diff --git a/template/python3-flask/Dockerfile b/template/python3-flask/Dockerfile index 52b661e..7af655e 100644 --- a/template/python3-flask/Dockerfile +++ b/template/python3-flask/Dockerfile @@ -5,6 +5,8 @@ COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog RUN chmod +x /usr/bin/fwatchdog ARG ADDITIONAL_PACKAGE +# Alternatively use ADD https:// (which will not be cached by Docker builder) + RUN apk --no-cache add musl-dev gcc make ${ADDITIONAL_PACKAGE} # Add non root user @@ -19,8 +21,11 @@ WORKDIR /home/app/ COPY index.py . COPY requirements.txt . + USER root RUN pip install -r requirements.txt + +#build function directory and install user specified componenets. USER app RUN mkdir -p function @@ -31,9 +36,13 @@ RUN pip install --user -r requirements.txt WORKDIR /home/app/ +#install function code USER root + COPY function function RUN chown -R app:app ./ + +#configure WSGI server and healthcheck USER app ENV fprocess="python index.py" diff --git a/template/python3-http-debian/Dockerfile b/template/python3-http-debian/Dockerfile new file mode 100644 index 0000000..9bdd87e --- /dev/null +++ b/template/python3-http-debian/Dockerfile @@ -0,0 +1,49 @@ +FROM openfaas/of-watchdog:0.7.2 as watchdog +FROM python:3.7-slim-buster + +COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog +RUN chmod +x /usr/bin/fwatchdog + +ARG ADDITIONAL_PACKAGE +# Alternatively use ADD https:// (which will not be cached by Docker builder) + +RUN apt-get -qy update && apt-get -qy install ${ADDITIONAL_PACKAGE} + +# Add non root user +RUN addgroup --system app && adduser app --system --ingroup app +RUN chown app /home/app + +USER app + +ENV PATH=$PATH:/home/app/.local/bin + +WORKDIR /home/app/ + +COPY index.py . +COPY requirements.txt . +USER root +RUN pip install -r requirements.txt +USER app + +RUN mkdir -p function +RUN touch ./function/__init__.py +WORKDIR /home/app/function/ +COPY function/requirements.txt . +RUN pip install --user -r requirements.txt + +WORKDIR /home/app/ + +USER root +COPY function function +RUN chown -R app:app ./ +USER app + +# Set up of-watchdog for HTTP mode +ENV fprocess="python index.py" +ENV cgi_headers="true" +ENV mode="http" +ENV upstream_url="http://127.0.0.1:5000" + +HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1 + +CMD ["fwatchdog"] \ No newline at end of file diff --git a/template/python3-http-debian/function/handler.py b/template/python3-http-debian/function/handler.py new file mode 100644 index 0000000..a1a099c --- /dev/null +++ b/template/python3-http-debian/function/handler.py @@ -0,0 +1,5 @@ +def handle(event, context): + return { + "statusCode": 200, + "body": "Hello from OpenFaaS!" + } diff --git a/template/python3-http-debian/function/requirements.txt b/template/python3-http-debian/function/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/template/python3-http-debian/index.py b/template/python3-http-debian/index.py new file mode 100644 index 0000000..71b8624 --- /dev/null +++ b/template/python3-http-debian/index.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +from flask import Flask, request, jsonify +from waitress import serve +import os + +from function import handler + +app = Flask(__name__) + +class Event: + def __init__(self): + self.body = request.get_data() + self.headers = request.headers + self.method = request.method + self.query = request.args + self.path = request.path + +class Context: + def __init__(self): + self.hostname = os.environ['HOSTNAME'] + +def format_status_code(resp): + if 'statusCode' in resp: + return resp['statusCode'] + + return 200 + +def format_body(resp): + if 'body' not in resp: + return "" + elif type(resp['body']) == dict: + return jsonify(resp['body']) + else: + return str(resp['body']) + +def format_headers(resp): + if 'headers' not in resp: + return [] + elif type(resp['headers']) == dict: + headers = [] + for key in resp['headers'].keys(): + header_tuple = (key, resp['headers'][key]) + headers.append(header_tuple) + return headers + + return resp['headers'] + +def format_response(resp): + if resp == None: + return ('', 200) + + statusCode = format_status_code(resp) + body = format_body(resp) + headers = format_headers(resp) + + return (body, statusCode, headers) + +@app.route('/', defaults={'path': ''}, methods=['GET', 'PUT', 'POST', 'PATCH', 'DELETE']) +@app.route('/', methods=['GET', 'PUT', 'POST', 'PATCH', 'DELETE']) +def call_handler(path): + event = Event() + context = Context() + response_data = handler.handle(event, context) + + resp = format_response(response_data) + return resp + +if __name__ == '__main__': + serve(app, host='0.0.0.0', port=5000) \ No newline at end of file diff --git a/template/python3-http-debian/requirements.txt b/template/python3-http-debian/requirements.txt new file mode 100644 index 0000000..8642e2b --- /dev/null +++ b/template/python3-http-debian/requirements.txt @@ -0,0 +1,2 @@ +flask +waitress \ No newline at end of file diff --git a/template/python3-http-debian/template.yml b/template/python3-http-debian/template.yml new file mode 100644 index 0000000..36ef6ef --- /dev/null +++ b/template/python3-http-debian/template.yml @@ -0,0 +1,2 @@ +language: python3-http-debian +fprocess: python index.py diff --git a/template/python3-http/Dockerfile b/template/python3-http/Dockerfile index 2a8bf73..a0349c3 100644 --- a/template/python3-http/Dockerfile +++ b/template/python3-http/Dockerfile @@ -6,6 +6,7 @@ RUN chmod +x /usr/bin/fwatchdog ARG ADDITIONAL_PACKAGE # Alternatively use ADD https:// (which will not be cached by Docker builder) + RUN apk --no-cache add ${ADDITIONAL_PACKAGE} # Add non root user @@ -22,6 +23,8 @@ COPY index.py . COPY requirements.txt . USER root RUN pip install -r requirements.txt + +#build function directory and install user specified componenets. USER app RUN mkdir -p function @@ -32,12 +35,14 @@ RUN pip install --user -r requirements.txt WORKDIR /home/app/ +#install function code USER root COPY function function RUN chown -R app:app ./ + +#configure WSGI server and healthcheck USER app -# Set up of-watchdog for HTTP mode ENV fprocess="python index.py" ENV cgi_headers="true" ENV mode="http"