-
-
Notifications
You must be signed in to change notification settings - Fork 74
Expand file tree
/
Copy pathhandler.js
More file actions
142 lines (125 loc) · 4.19 KB
/
handler.js
File metadata and controls
142 lines (125 loc) · 4.19 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
'use strict';
/**
* IMPORTANT: This file is cached, so when you test changes made to this file,
* make sure you delete the .serverless directory, and un-memoize the packaging code.
* For more info search for the "utils/ensure-artifact.js" file in the codebase.
*/
const { wait, MAX_AWS_REQUEST_TRY } = require('../utils');
const { getEnvironment, handlerWrapper } = require('../utils');
const {
APIGatewayClient,
GetAccountCommand,
UpdateAccountCommand,
} = require('@aws-sdk/client-api-gateway');
const {
IAMClient,
ListAttachedRolePoliciesCommand,
CreateRoleCommand,
AttachRolePolicyCommand,
} = require('@aws-sdk/client-iam');
const apiGateway = new APIGatewayClient({ maxAttempts: MAX_AWS_REQUEST_TRY });
const iam = new IAMClient({ maxAttempts: MAX_AWS_REQUEST_TRY });
async function handler(event, context) {
if (event.RequestType === 'Create') {
return create(event, context);
} else if (event.RequestType === 'Update') {
return update(event, context);
} else if (event.RequestType === 'Delete') {
return remove(event, context);
}
throw new Error(`Unhandled RequestType ${event.RequestType}`);
}
async function create(event, context) {
const { RoleArn } = event.ResourceProperties;
const { Partition: partition, AccountId: accountId, Region: region } = getEnvironment(context);
apiGateway.config.region = () => region;
iam.config.region = () => region;
const assignedRoleArn = (await apiGateway.send(new GetAccountCommand({}))).cloudwatchRoleArn;
let roleArn = `arn:${partition}:iam::${accountId}:role/serverlessApiGatewayCloudWatchRole`;
if (RoleArn) {
// if there's a roleArn in the Resource Properties, just re-use it here
roleArn = RoleArn;
} else {
// Create an own API Gateway role if the roleArn was not set via Resource Properties
const apiGatewayPushToCloudWatchLogsPolicyArn = `arn:${partition}:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs`;
const roleName = roleArn.slice(roleArn.lastIndexOf('/') + 1);
const attachedPolicies = await (async () => {
try {
return (await iam.send(new ListAttachedRolePoliciesCommand({ RoleName: roleName })))
.AttachedPolicies;
} catch (error) {
if (error.code === 'NoSuchEntity' || error.message.includes('cannot be found')) {
// Role doesn't exist yet, create;
await iam.send(
new CreateRoleCommand({
AssumeRolePolicyDocument: JSON.stringify({
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Principal: {
Service: ['apigateway.amazonaws.com'],
},
Action: ['sts:AssumeRole'],
},
],
}),
Path: '/',
RoleName: roleName,
})
);
return [];
}
throw error;
}
})();
if (
!attachedPolicies.some(
(policy) => policy.PolicyArn === apiGatewayPushToCloudWatchLogsPolicyArn
)
) {
await iam.send(
new AttachRolePolicyCommand({
PolicyArn: apiGatewayPushToCloudWatchLogsPolicyArn,
RoleName: roleName,
})
);
}
}
// there's nothing to do if the role is the same
if (roleArn === assignedRoleArn) return null;
const updateAccount = async (counter = 1) => {
try {
await apiGateway.send(
new UpdateAccountCommand({
patchOperations: [
{
op: 'replace',
path: '/cloudwatchRoleArn',
value: roleArn,
},
],
})
);
} catch (error) {
if (counter < 10) {
// Observed fails with errors marked as non-retryable. Still they're outcome of
// temporary state where just created AWS role is not being ready for use (yet)
await wait(10000);
return updateAccount(++counter);
}
throw error;
}
return null;
};
return updateAccount();
}
function update() {
// No actions
}
function remove() {
// No actions
}
module.exports = {
handler: handlerWrapper(handler, 'CustomResourceApiGatewayAccountCloudWatchRole'),
};