-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
sspa
executable file
·381 lines (342 loc) · 9.9 KB
/
sspa
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
#!/usr/bin/env bash
abspath="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"
root_dir=`dirname "$abspath"`
app_name=learnjs
code_bucket=${app_name}/_code_bundles
profile=admin
function check_python() {
if ! which python > /dev/null; then
echo "Can't find Python. You need Python 2.7 or later to use this."
exit 1
fi
}
function check_aws() {
if ! which aws > /dev/null; then
echo "Can't find AWS CLI. Install 'awscli' using pip."
exit 1
fi
if ! aws configure list --profile $profile > /dev/null; then
echo "Run \`aws configure --profile $profile\` to create it"
exit 1
fi
}
function check_node_deps() {
if ! which npm > /dev/null; then
echo "This action requires Node.js and NPM."
exit 1
fi
}
function dev_server() {
cd public
ret=`python -c 'import sys; print("%i" % (sys.hexversion<0x03000000))'`
if [ $ret -eq 0 ]; then
exec python -m http.server 9292
else
exec python -m SimpleHTTPServer 9292
fi
}
function livereload_server() {
cd public
exec livereloadx -s -p 9292 "$PWD"
}
function create_s3_bucket() {
local bucket_name=$1
local bucket_uri="s3://${bucket_name}"
local bucket_path=conf/s3/${bucket_name}
# The s3 command doesn't output JSON :-/
if [[ ! -e ${bucket_path}/endpoint.txt ]]; then
aws --profile $profile s3 mb $bucket_uri && mkdir -p ${bucket_path}
local region=$(aws --profile $profile configure get region)
local endpoint="http://${1}.s3-website-${region}.amazonaws.com"
echo "$endpoint" > ${bucket_path}/endpoint.txt
echo "Website endpoint is: $endpoint"
fi
}
function webify_bucket() {
local bucket_name=$1
local bucket_uri="s3://${bucket_name}"
aws --profile $profile s3 website \
--index-document index.html \
--error-document error.html \
$bucket_uri
}
function deploy_s3_bucket() {
local bucket_name=$1
if [[ -d ${1} ]]; then
bucket_name=$(basename $bucket_name)
fi
local bucket_uri="s3://${1}"
aws --profile $profile s3 sync public/ $bucket_uri --acl public-read
}
function generate_assume_role_policy() {
local identity_pool_arn=$1
cat <<DOC
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "${identity_pool_arn}"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
DOC
}
function generate_table_policy() {
local table_arn=$1
cat <<DOC
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": ["${table_arn}"],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["\${cognito-identity.amazonaws.com:sub}"]}
}
}]
}
DOC
}
function create_cognito_auth_role() {
local identity_pool_dir=$1
local pool_id=$(support/jsed.py ${identity_pool_dir}/pool_info.json 'IdentityPoolId')
local pool_name=$(support/jsed.py ${identity_pool_dir}/pool_info.json 'IdentityPoolName')
generate_assume_role_policy ${pool_id} > ${identity_pool_dir}/assume_role_policy.json
if [[ ! -s ${identity_pool_dir}/role_info.json ]]; then
local role_name="${pool_name}_cognito_authenticated"
echo "Creaing role: $role_name"
# Might be able to use the create_iam_role function for this
aws --profile $profile iam create-role \
--role-name "$role_name" \
--assume-role-policy-document "file://${identity_pool_dir}/assume_role_policy.json" \
> ${identity_pool_dir}/role_info.json
fi
}
function create_identity_pool() {
local identity_pool_dir=${1%/}
if [[ ! -e ${identity_pool_dir}/config.json ]]; then
echo "Can't find pool config file ${identity_pool_dir}/config.json"
exit 1
fi
local identity_pool_name=$(basename $identity_pool_dir)
if [[ ! -s ${identity_pool_dir}/pool_info.json ]]; then
echo "Creating identity pool: $identity_pool_name"
aws --profile $profile cognito-identity create-identity-pool \
--identity-pool-name $identity_pool_name \
--cli-input-json "file://${identity_pool_dir}/config.json" \
> ${identity_pool_dir}/pool_info.json
fi
create_cognito_auth_role ${identity_pool_dir}
local pool_id=$(support/jsed.py ${identity_pool_dir}/pool_info.json 'IdentityPoolId')
local role_arn=$(support/jsed.py ${identity_pool_dir}/role_info.json 'Role.Arn')
echo "Updating identity pool roles"
aws --profile $profile cognito-identity set-identity-pool-roles \
--identity-pool-id ${pool_id} \
--roles authenticated=${role_arn}
}
function create_table() {
local table_dir=${1%/}
local table_name=$(basename $table_dir)
local role_name="${2}_cognito_authenticated"
if [[ ! -s ${table_dir}/table_info.json ]]; then
aws --profile $profile dynamodb create-table \
--table-name $table_name \
--cli-input-json "file://${table_dir}/config.json" \
> ${table_dir}/table_info.json
echo -n "Waiting for table creation..."
aws --profile $profile dynamodb describe-table --table-name "$table_name" > ${table_dir}/table_info.json
while [[ "$(support/jsed.py ${table_dir}/table_info.json 'Table.TableStatus')" != "ACTIVE" ]]; do
aws --profile $profile dynamodb describe-table --table-name "$table_name" > ${table_dir}/table_info.json
echo -n .
done
echo "...done!"
fi
local table_arn=$(support/jsed.py ${table_dir}/table_info.json 'Table.TableArn')
generate_table_policy ${table_arn} > ${table_dir}/role_policy.json
aws --profile $profile iam put-role-policy \
--policy-document file://${table_dir}/role_policy.json \
--role-name ${role_name} \
--policy-name ${table_name}_table_access
}
function build_bundle() {
check_node_deps
pushd services
rm archive.zip
npm install || exit 1
mkdir -p dist
cp -r node_modules dist/
cp -r lib/* dist/
cd dist
chmod -R a+r *
zip -r archive.zip *
mv archive.zip ..
cd ..
rm -rf dist
popd
}
function deploy_bundle {
for fn in `ls conf/lambda/functions`; do
aws --profile $profile lambda update-function-code \
--function-name $fn \
--zip-file "fileb://services/archive.zip" > conf/lambda/functions/$fn/info.json
done
}
function test_services() {
check_node_deps
cd services
if [[ ! -x node_modules/.bin/jasmine ]]; then
npm install || exit 1
fi
export PATH=node_modules/.bin:${PATH}
NODE_PATH=./lib jasmine
cd ..
}
function create_iam_role() {
local role_name="${app_name}_lambda_exec"
local role_dir=conf/iam/roles/${role_name}
local policy_document=$2
mkdir -p $role_dir
if [[ ! -e ${role_dir}/info.json ]]; then
aws --profile $profile iam create-role \
--role-name "$role_name" \
--assume-role-policy-document "${policy_document}" \
> ${role_dir}/info.json
fi
}
function create_lambda_service() {
local service_dir=${1%/}
local function_name=$(basename $service_dir)
create_iam_role lambda_exec "file://conf/iam/policies/lambda_trust.json"
echo -n "Waiting for IAM Role to become available..."
local role_arn=$(support/jsed.py conf/iam/roles/${app_name}_lambda_exec/info.json 'Role.Arn')
while ! aws --profile $profile iam get-role --role-name ${app_name}_lambda_exec &> /dev/null; do
echo -n .
done
sleep 5 # See issue #17
echo "...done!"
if [[ ! -e ${service_dir}/info.json ]]; then
aws --profile $profile lambda create-function \
--function-name ${function_name} \
--role ${role_arn} \
--runtime nodejs4.3 \
--zip-file "fileb://services/archive.zip" \
--handler "index.${function_name}" \
--cli-input-json "file://${service_dir}/config.json" \
> ${service_dir}/info.json
fi
}
function help() {
echo "#################################################"
echo "# Serverless Single Page Apps - The Bash Helper #"
echo "#################################################"
echo
echo "Usage: sspa <action> [arguments...]"
echo
echo "Where <action> is one of:"
echo " server"
echo " liveserver"
echo " create_bucket <bucket name>"
echo " deploy_bucket <bucket name>"
echo " create_pool <config dir>"
echo " create_table <config dir> <pool name>"
echo " test"
echo " build_bundle"
echo " deploy_bundle"
echo " create_service <config file>"
#echo " create_gateway <config_file> <service> - Attach an API Gateway to a service"
echo
}
action=${1:-"help"}
cd "$root_dir"
check_python
case "$action" in
liveserver)
livereload_server
;;
server)
dev_server
;;
test)
test_services
;;
build_bundle)
build_bundle
;;
deploy_bundle)
check_aws
build_bundle
deploy_bundle
;;
create_bucket)
check_aws
if [[ $# -eq 2 ]]; then
create_s3_bucket ${2}
webify_bucket ${2}
else
echo "Please specify a bucket name"
exit 1
fi
;;
deploy_bucket)
check_aws
if [[ $# -eq 2 ]]; then
deploy_s3_bucket ${2}
else
echo "Please specify an S3 bucket name"
exit 1
fi
;;
create_pool)
check_aws
if [[ $# -eq 2 ]]; then
create_identity_pool ${2}
else
echo "Please specify a Cognito identity pool configuration directory"
exit 1
fi
;;
create_table)
check_aws
if [[ $# -eq 3 ]]; then
create_table ${2} ${3}
else
echo "Please specify a DynamoDB table configuration directory and identity pool name"
exit 1
fi
;;
create_service)
check_aws
if [[ $# -eq 2 ]]; then
build_bundle
create_lambda_service ${2}
else
echo "Please specify a Lambda config directory"
exit 1
fi
;;
*)
help
;;
esac