-
Notifications
You must be signed in to change notification settings - Fork 88
/
wsgi_handler.py
116 lines (92 loc) · 3.7 KB
/
wsgi_handler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This module loads the WSGI application specified by FQN in `.serverless-wsgi` and invokes
the request when the handler is called by AWS Lambda.
Author: Logan Raarup <logan@logan.dk>
"""
import importlib
import io
import json
import os
import sys
import traceback
# Call decompression helper from `serverless-python-requirements` if
# available. See: https://github.com/UnitedIncome/serverless-python-requirements#dealing-with-lambdas-size-limitations
try:
import unzip_requirements # noqa
except ImportError:
pass
import serverless_wsgi
def load_config():
"""Read the configuration file created during deployment"""
root = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(root, ".serverless-wsgi"), "r") as f:
return json.loads(f.read())
def import_app(config):
"""Load the application WSGI handler"""
wsgi_fqn = config["app"].rsplit(".", 1)
wsgi_fqn_parts = wsgi_fqn[0].rsplit("/", 1)
if len(wsgi_fqn_parts) == 2:
root = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(root, wsgi_fqn_parts[0]))
try:
wsgi_module = importlib.import_module(wsgi_fqn_parts[-1])
return getattr(wsgi_module, wsgi_fqn[1])
except: # noqa
traceback.print_exc()
raise Exception("Unable to import {}".format(config["app"]))
def append_text_mime_types(config):
"""Append additional text (non-base64) mime types from configuration file"""
if "text_mime_types" in config and isinstance(config["text_mime_types"], list):
serverless_wsgi.TEXT_MIME_TYPES.extend(config["text_mime_types"])
def handler(event, context):
"""Lambda event handler, invokes the WSGI wrapper and handles command invocation"""
if "_serverless-wsgi" in event:
import shlex
import subprocess
native_stdout = sys.stdout
native_stderr = sys.stderr
output_buffer = io.StringIO()
try:
sys.stdout = output_buffer
sys.stderr = output_buffer
meta = event["_serverless-wsgi"]
if meta.get("command") == "exec":
# Evaluate Python code
exec(meta.get("data", ""))
elif meta.get("command") == "command":
# Run shell commands
result = subprocess.check_output(
meta.get("data", ""), shell=True, stderr=subprocess.STDOUT
)
output_buffer.write(result.decode())
elif meta.get("command") == "manage":
# Run Django management commands
from django.core import management
management.call_command(*shlex.split(meta.get("data", "")))
elif meta.get("command") == "flask":
# Run Flask CLI commands
from flask.cli import FlaskGroup
flask_group = FlaskGroup(create_app=_create_app)
flask_group.main(
shlex.split(meta.get("data", "")), standalone_mode=False
)
else:
raise Exception("Unknown command: {}".format(meta.get("command")))
except subprocess.CalledProcessError as e:
return [e.returncode, e.output.decode("utf-8")]
except: # noqa
return [1, traceback.format_exc()]
finally:
sys.stdout = native_stdout
sys.stderr = native_stderr
return [0, output_buffer.getvalue()]
else:
return serverless_wsgi.handle_request(wsgi_app, event, context)
def _create_app():
return wsgi_app
# Read configuration and import the WSGI application
config = load_config()
wsgi_app = import_app(config)
append_text_mime_types(config)