-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add endpoints structure and error handlers
- Loading branch information
Sergey Shelomentsev
committed
Dec 19, 2023
1 parent
850ca61
commit f5b3709
Showing
5 changed files
with
189 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { APIGatewayProxyResult } from 'aws-lambda' | ||
|
||
export async function handleNoAthentication(): Promise<APIGatewayProxyResult> { | ||
const body = { | ||
status: 'Token is not specified or not valid', | ||
} | ||
return { | ||
statusCode: 401, | ||
body: JSON.stringify(body), | ||
} | ||
} | ||
|
||
export async function handleWrongConfiguration(error: any): Promise<APIGatewayProxyResult> { | ||
const body = { | ||
status: | ||
'Wrong function configuration. Check environment variables for Lambda@Edge function and CloudFront Distribution id', | ||
error: error, | ||
} | ||
return { | ||
statusCode: 500, | ||
body: JSON.stringify(body), | ||
} | ||
} | ||
|
||
export async function handleNotFound(): Promise<APIGatewayProxyResult> { | ||
const body = { | ||
status: 'Path not found', | ||
} | ||
return { | ||
statusCode: 404, | ||
body: JSON.stringify(body), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import type { DeploymentSettings } from '../model/DeploymentSettings' | ||
import { LambdaClient, GetFunctionCommand } from '@aws-sdk/client-lambda' | ||
|
||
export async function handleStatus(settings: DeploymentSettings) { | ||
const client = new LambdaClient({}) | ||
const command = new GetFunctionCommand({ FunctionName: settings.LambdaFunctionName }) | ||
const functionResult = await client.send(command) | ||
|
||
return { | ||
status: '200', | ||
body: functionResult, | ||
headers: { | ||
'content-type': 'application/json', | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import type { DeploymentSettings } from '../model/DeploymentSettings' | ||
import { defaults } from '../model/DefaultSettings' | ||
import { | ||
CloudFrontClient, | ||
CreateInvalidationCommand, | ||
CreateInvalidationCommandInput, | ||
GetDistributionConfigCommand, | ||
GetDistributionConfigCommandOutput, | ||
UpdateDistributionCommand, | ||
UpdateDistributionCommandInput, | ||
} from '@aws-sdk/client-cloudfront' | ||
import { | ||
LambdaClient, | ||
ListVersionsByFunctionCommand, | ||
ListVersionsByFunctionCommandInput, | ||
ListVersionsByFunctionCommandOutput, | ||
} from '@aws-sdk/client-lambda' | ||
|
||
export async function handleUpdate(settings: DeploymentSettings) { | ||
console.info(`Going to upgrade Fingerprint Pro function association at CloudFront distbution.`) | ||
console.info(`Settings: ${settings}`) | ||
|
||
const latestFunctionArn = await getLambdaLatestVersionArn(settings.LambdaFunctionName) | ||
if (!latestFunctionArn) { | ||
return publishJobFailure('No lambda versions') | ||
} | ||
|
||
if (latestFunctionArn.length === 1) { | ||
console.info('No updates yet') | ||
return publishJobSuccess() | ||
} | ||
|
||
updateCloudFrontConfig(settings.CFDistributionId, settings.LambdaFunctionName, latestFunctionArn) | ||
} | ||
|
||
async function updateCloudFrontConfig( | ||
cloudFrontDistributionId: string, | ||
lambdaFunctionName: string, | ||
latestFunctionArn: string, | ||
) { | ||
const cloudFrontClient = new CloudFrontClient({ region: defaults.AWS_REGION }) | ||
|
||
const configParams = { | ||
Id: cloudFrontDistributionId, | ||
} | ||
const getConfigCommand = new GetDistributionConfigCommand(configParams) | ||
const cfConfig: GetDistributionConfigCommandOutput = await cloudFrontClient.send(getConfigCommand) | ||
|
||
if (!cfConfig.ETag || !cfConfig.DistributionConfig) { | ||
return publishJobFailure('CloudFront distribution not found') | ||
} | ||
|
||
const cacheBehaviors = cfConfig.DistributionConfig.CacheBehaviors | ||
const fpCbs = cacheBehaviors?.Items?.filter((it) => it.TargetOriginId === 'fpcdn.io') | ||
if (!fpCbs || fpCbs?.length === 0) { | ||
return publishJobFailure('Cache behavior not found') | ||
} | ||
const cacheBehavior = fpCbs[0] | ||
const lambdas = cacheBehavior.LambdaFunctionAssociations?.Items?.filter( | ||
(it) => it && it.EventType === 'origin-request' && it.LambdaFunctionARN?.includes(lambdaFunctionName), | ||
) | ||
if (!lambdas || lambdas?.length === 0) { | ||
return publishJobFailure('Lambda function association not found') | ||
} | ||
const lambda = lambdas[0] | ||
lambda.LambdaFunctionARN = latestFunctionArn | ||
|
||
const updateParams: UpdateDistributionCommandInput = { | ||
DistributionConfig: cfConfig.DistributionConfig, | ||
Id: cloudFrontDistributionId, | ||
IfMatch: cfConfig.ETag, | ||
} | ||
|
||
const updateConfigCommand = new UpdateDistributionCommand(updateParams) | ||
const updateCFResult = await cloudFrontClient.send(updateConfigCommand) | ||
console.info(`CloudFront update has finished, ${JSON.stringify(updateCFResult)}`) | ||
|
||
console.info('Going to invalidate routes for upgraded cache behavior') | ||
if (!cacheBehavior.PathPattern) { | ||
return publishJobFailure('Path pattern is not defined') | ||
} | ||
|
||
let pathPattern = cacheBehavior.PathPattern | ||
if (!pathPattern.startsWith('/')) { | ||
pathPattern = '/' + pathPattern | ||
} | ||
|
||
const invalidationParams: CreateInvalidationCommandInput = { | ||
DistributionId: cloudFrontDistributionId, | ||
InvalidationBatch: { | ||
Paths: { | ||
Quantity: 1, | ||
Items: [pathPattern], | ||
}, | ||
CallerReference: 'fingerprint-pro-management-lambda-function', | ||
}, | ||
} | ||
const invalidationCommand = new CreateInvalidationCommand(invalidationParams) | ||
const invalidationResult = await cloudFrontClient.send(invalidationCommand) | ||
console.info(`Invalidation has finished, ${JSON.stringify(invalidationResult)}`) | ||
} | ||
|
||
async function getLambdaLatestVersionArn(functionName: string): Promise<string | undefined> { | ||
const client = new LambdaClient({ region: REGION }) | ||
const params: ListVersionsByFunctionCommandInput = { | ||
FunctionName: functionName, | ||
} | ||
const command = new ListVersionsByFunctionCommand(params) | ||
const result: ListVersionsByFunctionCommandOutput = await client.send(command) | ||
if (!result.Versions || result.Versions?.length === 0) { | ||
return Promise.resolve(undefined) | ||
} | ||
|
||
const latest = result.Versions.filter((it) => it.Version && Number.isFinite(Number.parseInt(it.Version))).sort( | ||
(a, b) => Number.parseInt(b.Version!!) - Number.parseInt(a.Version!!), | ||
)[0] | ||
return Promise.resolve(latest.FunctionArn) | ||
} | ||
|
||
async function publishJobSuccess() { | ||
console.info(`Job successfully finished`) | ||
} | ||
|
||
async function publishJobFailure(message: string) { | ||
console.info(`Job failed with ${message}`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const defaults = { | ||
AWS_REGION: 'us-east-1', | ||
} |