-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Expand file tree
/
Copy pathindex.ts
More file actions
118 lines (105 loc) · 3.43 KB
/
Copy pathindex.ts
File metadata and controls
118 lines (105 loc) · 3.43 KB
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
// tslint:disable:no-console
import AWS = require('aws-sdk');
import { AwsSdkCall } from '../aws-custom-resource';
/**
* Flattens a nested object
*
* @param object the object to be flattened
* @returns a flat object with path as keys
*/
function flatten(object: object): { [key: string]: string } {
return Object.assign(
{},
...function _flatten(child: any, path: string[] = []): any {
return [].concat(...Object.keys(child)
.map(key =>
typeof child[key] === 'object'
? _flatten(child[key], path.concat([key]))
: ({ [path.concat([key]).join('.')]: child[key] })
));
}(object)
);
}
/**
* Converts true/false strings to booleans in an object
*/
function fixBooleans(object: object) {
return JSON.parse(JSON.stringify(object), (_k, v) => v === 'true'
? true
: v === 'false'
? false
: v);
}
/**
* Filters the keys of an object.
*/
function filterKeys(object: object, pred: (key: string) => boolean) {
return Object.entries(object)
.reduce(
(acc, [k, v]) => pred(k)
? { ...acc, [k]: v }
: acc,
{}
);
}
export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent, context: AWSLambda.Context) {
try {
console.log(JSON.stringify(event));
console.log('AWS SDK VERSION: ' + (AWS as any).VERSION);
let physicalResourceId = (event as any).PhysicalResourceId;
let flatData: { [key: string]: string } = {};
let data: { [key: string]: string } = {};
const call: AwsSdkCall | undefined = event.ResourceProperties[event.RequestType];
if (call) {
const awsService = new (AWS as any)[call.service](call.apiVersion && { apiVersion: call.apiVersion });
try {
const response = await awsService[call.action](call.parameters && fixBooleans(call.parameters)).promise();
flatData = flatten(response);
data = call.outputPath
? filterKeys(flatData, k => k.startsWith(call.outputPath!))
: flatData;
} catch (e) {
if (!call.catchErrorPattern || !new RegExp(call.catchErrorPattern).test(e.code)) {
throw e;
}
}
physicalResourceId = call.physicalResourceIdPath
? flatData[call.physicalResourceIdPath]
: call.physicalResourceId;
}
await respond('SUCCESS', 'OK', physicalResourceId, data);
} catch (e) {
console.log(e);
await respond('FAILED', e.message || 'Internal Error', context.logStreamName, {});
}
function respond(responseStatus: string, reason: string, physicalResourceId: string, data: any) {
const responseBody = JSON.stringify({
Status: responseStatus,
Reason: reason,
PhysicalResourceId: physicalResourceId,
StackId: event.StackId,
RequestId: event.RequestId,
LogicalResourceId: event.LogicalResourceId,
NoEcho: false,
Data: data
});
console.log('Responding', responseBody);
const parsedUrl = require('url').parse(event.ResponseURL);
const requestOptions = {
hostname: parsedUrl.hostname,
path: parsedUrl.path,
method: 'PUT',
headers: { 'content-type': '', 'content-length': responseBody.length }
};
return new Promise((resolve, reject) => {
try {
const request = require('https').request(requestOptions, resolve);
request.on('error', reject);
request.write(responseBody);
request.end();
} catch (e) {
reject(e);
}
});
}
}