-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update the handler to match style of golang-http-template
- Created two new templates, python3-http & python3-http-armhf - Added waitress as the production server for new templates Signed-off-by: Kevin Turcios <kevin_turcios@outlook.com>
- Loading branch information
Showing
14 changed files
with
421 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
*.pyc | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,158 @@ | ||
# python-flask-template | ||
OpenFaaS Python Flask Templates | ||
============================================= | ||
|
||
Python OpenFaaS template with Flask | ||
The Python Flask templates make use of the incubator project [of-watchdog](https://github.com/openfaas-incubator/of-watchdog) to handle higher throughput than the [classic watchdog](https://github.com/openfaas/faas/tree/master/watchdog) due to the process being kept warm. | ||
|
||
To try this out with either Python 2.7 or Python 3.6: | ||
|
||
```bash | ||
faas template pull https://github.com/openfaas-incubator/python-flask-template | ||
faas new --list | ||
Languages available as templates: | ||
Templates available under this repository: | ||
- python27-flask | ||
- python3-flask | ||
``` | ||
- python3-flask-armhf | ||
- python3-http* | ||
- python3-http-armhf* | ||
|
||
Generate a function with one of the languages: | ||
Notes: | ||
- The templates listed with an asterik are the only ones that support additional control over the HTTP response and provide access to HTTP request details. | ||
- To build and deploy a function for Raspberry Pi or ARMv7 in general, use the language templates ending in *-armhf* | ||
|
||
```bash | ||
faas new --lang python3-flask myfunction | ||
mv myfunction.yml stack.yml | ||
## Downloading the templates | ||
``` | ||
$ faas template pull https://github.com/openfaas-incubator/python-flask-template | ||
``` | ||
|
||
Followed by the usual flow: | ||
# Using the python27-flask/python3-flask templates | ||
Create a new function | ||
``` | ||
$ faas new --lang python27-flask <fn-name> | ||
``` | ||
Build, push, and deploy | ||
``` | ||
$ faas up -f <fn-name>.yml | ||
``` | ||
Test the new function | ||
``` | ||
$ echo -n content | faas invoke <fn-name> | ||
``` | ||
|
||
# Using the python3-http templates | ||
Create a new function | ||
``` | ||
$ faas new --lang python3-http <fn-name> | ||
``` | ||
Build, push, and deploy | ||
``` | ||
$ faas up -f <fn-name>.yml | ||
``` | ||
Set your OpenFaaS gateway URL. For example: | ||
``` | ||
faas build \ | ||
&& faas deploy | ||
&& faas list --verbose | ||
$ OPENFAAS_URL=http://127.0.0.1:8080 | ||
``` | ||
Test the new function | ||
``` | ||
$ curl -i $OPENFAAS_URL/function/<fn-name> | ||
``` | ||
|
||
## Event and Context Data | ||
The function handler is passed two arguments, *event* and *context*. | ||
|
||
*event* contains data about the request, including: | ||
- body | ||
- headers | ||
- method | ||
- query | ||
- path | ||
|
||
*context* contains basic information about the function, including: | ||
- hostname | ||
|
||
## Response Bodies | ||
By default, flask will automatically attempt to set the correct Content-Type header for you based on the type of response. | ||
|
||
# Wait a couple of seconds then: | ||
For example, returning a dict object type will automatically attach the header `Content-Type: application/json` and returning a string type will automatically attach the `Content-Type: text/html, charset=utf-8` for you. | ||
|
||
echo -n content | faas invoke myfunction | ||
## Example usage | ||
### Custom Status Codes and Response Bodies | ||
Successful response status code and JSON response body | ||
```python | ||
def handle(event, context): | ||
return { | ||
"statusCode": 200, | ||
"body": { | ||
"key": "value" | ||
} | ||
} | ||
``` | ||
Successful response status code and string response body | ||
```python | ||
def handle(event, context): | ||
return { | ||
"statusCode": 201, | ||
"body": "Object successfully created" | ||
} | ||
``` | ||
Failure response status code and JSON error message | ||
```python | ||
def handle(event, context): | ||
return { | ||
"statusCode": 400, | ||
"body": { | ||
"error": "Bad request" | ||
} | ||
} | ||
``` | ||
### Custom Response Headers | ||
Setting custom response headers | ||
```python | ||
def handle(event, context): | ||
return { | ||
"statusCode": 200, | ||
"body": { | ||
"key": "value" | ||
}, | ||
"headers": { | ||
"Location": "https://www.example.com/" | ||
} | ||
} | ||
``` | ||
### Accessing Event Data | ||
Accessing request body | ||
```python | ||
def handle(event, context): | ||
return { | ||
"statusCode": 200, | ||
"body": "You said: " + str(event.body) | ||
} | ||
``` | ||
Accessing request method | ||
```python | ||
def handle(event, context): | ||
if event.method == 'GET': | ||
return { | ||
"statusCode": 200, | ||
"body": "GET request" | ||
} | ||
else: | ||
return { | ||
"statusCode": 405, | ||
"body": "Method not allowed" | ||
} | ||
``` | ||
Accessing request query string arguments | ||
```python | ||
def handle(event, context): | ||
return { | ||
"statusCode": 200, | ||
"body": { | ||
"name": event.query['name'] | ||
} | ||
} | ||
``` | ||
Accessing request headers | ||
```python | ||
def handle(event, context): | ||
return { | ||
"statusCode": 200, | ||
"body": { | ||
"content-type-received": event.headers['Content-Type'] | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
FROM armhf/python:3.6-alpine | ||
|
||
ARG ADDITIONAL_PACKAGE | ||
# Alternatively use ADD https:// (which will not be cached by Docker builder) | ||
RUN apk --no-cache add curl ${ADDITIONAL_PACKAGE} \ | ||
&& echo "Pulling watchdog binary from Github." \ | ||
&& curl -sSLf https://github.com/openfaas-incubator/of-watchdog/releases/download/0.4.6/of-watchdog-armhf > /usr/bin/fwatchdog \ | ||
&& chmod +x /usr/bin/fwatchdog \ | ||
&& apk del curl --no-cache | ||
|
||
# Add non root user | ||
RUN addgroup -S app && adduser app -S -G 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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
def handle(event, context): | ||
# TODO implement | ||
return { | ||
"statusCode": 200, | ||
"body": "Hello from OpenFaaS!" | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
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('/<path:path>', 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
flask | ||
waitress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
language: python3-http-armhf | ||
fprocess: python index.py | ||
build_options: | ||
- name: dev | ||
packages: | ||
- make | ||
- automake | ||
- gcc | ||
- g++ | ||
- subversion | ||
- python3-dev | ||
- musl-dev | ||
- libffi-dev | ||
- git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
FROM python:3.7-alpine | ||
|
||
ARG ADDITIONAL_PACKAGE | ||
# Alternatively use ADD https:// (which will not be cached by Docker builder) | ||
RUN apk --no-cache add curl ${ADDITIONAL_PACKAGE} \ | ||
&& echo "Pulling watchdog binary from Github." \ | ||
&& curl -sSLf https://github.com/openfaas-incubator/of-watchdog/releases/download/0.4.6/of-watchdog > /usr/bin/fwatchdog \ | ||
&& chmod +x /usr/bin/fwatchdog \ | ||
&& apk del curl --no-cache | ||
|
||
# Add non root user | ||
RUN addgroup -S app && adduser app -S -G 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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
def handle(event, context): | ||
# TODO implement | ||
return { | ||
"statusCode": 200, | ||
"body": "Hello from OpenFaaS!" | ||
} |
Empty file.
Oops, something went wrong.