-
Notifications
You must be signed in to change notification settings - Fork 41
/
bootstrap
executable file
·139 lines (124 loc) · 4.97 KB
/
bootstrap
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/bin/sh
set -euo pipefail
SCRIPT_DIR=$(cd $(dirname $0); pwd)
HANDLER_NAME=$(echo "$_HANDLER" | cut -d. -f2)
HANDLER_FILE=$(echo "$_HANDLER" | cut -d. -f1)
API_ROOT=http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/
# If this ENV variable is set then copy that directory as DENO_DIR (default = .deno_dir).
# Note: For permissions reasons we need the actual DENO_DIR to be somewhere in /tmp.
DENO_DIR=${DENO_DIR-.deno_dir}
if [[ -z "$DENO_DIR" ]]; then
DENO_DIR=.deno_dir
fi
# whether to use ts, js, bundle.js, etc.
HANDLER_EXT=${HANDLER_EXT-'ts'}
HANDLER_FILE=${HANDLER_FILE}.${HANDLER_EXT}
# If we fail prior to the handler loop we post an init error.
function error {
echo "error:" $1
ERROR="{\"errorMessage\" : \"$1\", \"errorType\" : \"InitException\"}"
curl -s -X POST "${API_ROOT}init/error" \
-d "$ERROR" \
--header "Lambda-Runtime-Function-Error-Type: Unhandled" \
--output /tmp/init.out
# expect it to be {"status":"OK"}
grep -q OK /tmp/init.out \
|| echo "Unexpected bootstrap error when calling AWS_LAMBDA_RUNTIME_API /init/error:" $(cat /tmp/init.out)
exit 1
}
# If the script fails we try and determine why.
function investigate {
[ -f $SCRIPT_DIR/amz-deno ] \
|| error "missing amz-deno executable"
$SCRIPT_DIR/amz-deno eval 'Deno.version.deno' \
|| error "bad amz-deno executable"
[ -f $LAMBDA_TASK_ROOT/$HANDLER_FILE ] \
|| error "missing expected handler file '$HANDLER_FILE'"
DENO_DIR=/tmp/deno_dir NO_COLOR=true $SCRIPT_DIR/amz-deno fetch $LAMBDA_TASK_ROOT/$HANDLER_FILE \
|| error "unable to compile $HANDLER_FILE"
echo "import { $HANDLER_NAME } from '$LAMBDA_TASK_ROOT/$HANDLER_FILE';" > /tmp/runtime-test.js
DENO_DIR=/tmp/deno_dir NO_COLOR=true $SCRIPT_DIR/amz-deno fetch /tmp/runtime-test.js 2> /dev/null \
|| error "$HANDLER_FILE must export a function named '$HANDLER_NAME'";
# perhaps a bug in bootstrap? Should we always exit 1?
}
# Note: This is a js file to avoid a runtime compilation step.
# Hopefully $HANDLER_FILE's compilation is cached in DENO_DIR.
echo "
import { $HANDLER_NAME } from '$LAMBDA_TASK_ROOT/$HANDLER_FILE';
const INVOCATION = '${API_ROOT}invocation/';
while (true) {
const next = await fetch(INVOCATION + 'next');
const headers = next.headers;
const reqId = headers.get('Lambda-Runtime-Aws-Request-Id');
const context = {
functionName: '$AWS_LAMBDA_FUNCTION_NAME',
functionVersion: '$AWS_LAMBDA_FUNCTION_VERSION',
invokedFunctionArn: headers.get('lambda-runtime-invoked-function-arn'),
memoryLimitInMB: $AWS_LAMBDA_FUNCTION_MEMORY_SIZE,
awsRequestId: headers.get('lambda-runtime-aws-request-id'),
logGroupName: '$AWS_LAMBDA_LOG_GROUP_NAME',
logStreamName: '$AWS_LAMBDA_LOG_STREAM_NAME',
identity: undefined,
clientContext: undefined,
getRemainingTimeInMillis: function() {
return Number(headers.get('lambda-runtime-deadline-ms')) - Date.now();
}
}
let res;
try {
const event = await next.json();
const body = await $HANDLER_NAME(event, context);
res = await fetch(INVOCATION + reqId + '/response', {
method: 'POST',
body: JSON.stringify(body)
});
} catch(e) {
console.error(e);
// If it's an Error we can pull these out cleanly...
// BUT it's javascript so it could be anything!
// If there's a better way, very happy to take suggestions.
let name, message;
try {
name = e.name || 'Error'
} catch (_) {
name = 'Error'
}
try {
message = e.message || e
} catch (_) {
message = e
}
if (typeof(name) !== 'string') {
name = JSON.stringify(name)
}
if (typeof(message) !== 'string') {
const s = JSON.stringify(message)
message = s === undefined ? '' + message : s
}
res = await fetch(INVOCATION + reqId + '/error', {
method: 'POST',
body: JSON.stringify({
errorMessage: message,
errorType: name
})
});
}
await res.blob();
}
" > /tmp/runtime.js
# We copy DENO_DIR into a writable directory (/tmp/deno_dir)
# and expand DENO_DIR/LAMBDA_TASK_ROOT to match the new location ($LAMBDA_TASK_ROOT).
mkdir -p /tmp/deno_dir/gen/file$LAMBDA_TASK_ROOT
# We cp first from the deno-lambda-layer.
cp -R /opt/.deno_dir/gen/. /tmp/deno_dir/gen &> /dev/null \
&& cp -R /opt/.deno_dir/deps/. /tmp/deno_dir/deps &> /dev/null \
&& cp -R /opt/.deno_dir/LAMBDA_TASK_ROOT/. /tmp/deno_dir/gen/file$LAMBDA_TASK_ROOT &> /dev/null \
|| true
# Then we overwrite with from the DENO_DIR in the function code.
cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/gen/. /tmp/deno_dir/gen &> /dev/null \
&& cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/deps/. /tmp/deno_dir/deps &> /dev/null \
&& cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/gen/. /tmp/deno_dir/gen &> /dev/null \
&& cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/LAMBDA_TASK_ROOT/. /tmp/deno_dir/gen/file$LAMBDA_TASK_ROOT &> /dev/null \
|| echo "warn: unable to import '$DENO_DIR/' as DENO_DIR"
DENO_DIR=/tmp/deno_dir NO_COLOR=true $SCRIPT_DIR/amz-deno run --allow-net --allow-read --allow-env /tmp/runtime.js \
|| investigate;