mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
* fix(apig): fix enabling api gateway logs * chore: update comment * docs: update apig logs docs
158 lines
4.3 KiB
JavaScript
158 lines
4.3 KiB
JavaScript
'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',
|
|
),
|
|
}
|