Skip to content

Commit

Permalink
feat: update lambda existence check
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Shelomentsev committed Feb 26, 2024
1 parent 09820f7 commit 403680c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 46 deletions.
32 changes: 14 additions & 18 deletions mgmt-lambda/handlers/updateHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import {
} from '@aws-sdk/client-cloudfront'
import {
LambdaClient,
ListVersionsByFunctionCommand,
ListVersionsByFunctionCommandInput,
ListVersionsByFunctionCommandOutput,
GetFunctionCommand,
UpdateFunctionCodeCommand,
GetFunctionCommandInput,
GetFunctionCommandOutput,
} from '@aws-sdk/client-lambda'

export async function handleUpdate(
Expand All @@ -26,9 +26,9 @@ export async function handleUpdate(
console.info(`Going to upgrade Fingerprint Pro function association at CloudFront distbution.`)
console.info(`Settings: ${settings}`)

const latestFunctionArn = await getLambdaLatestVersionArn(lambdaClient, settings.LambdaFunctionName)
if (!latestFunctionArn) {
return handleFailure('No lambda version')
const isLambdaFunctionExist = await checkLambdaFunctionExistance(lambdaClient, settings.LambdaFunctionName)
if (!isLambdaFunctionExist) {
return handleFailure(`Lambda function with name ${settings.LambdaFunctionName} not found`)
}

try {
Expand Down Expand Up @@ -67,7 +67,7 @@ async function updateCloudFrontConfig(
}
const cacheBehavior = fpCbs[0]
const lambdas = cacheBehavior.LambdaFunctionAssociations?.Items?.filter(
(it) => it && it.EventType === 'origin-request' && it.LambdaFunctionARN?.includes(lambdaFunctionName),
(it) => it && it.EventType === 'origin-request' && it.LambdaFunctionARN?.includes(`${lambdaFunctionName}:`),
)
if (!lambdas || lambdas?.length === 0) {
return handleFailure('Lambda function association not found')
Expand Down Expand Up @@ -130,20 +130,16 @@ async function updateLambdaFunctionCode(lambdaClient: LambdaClient, functionName
return result.FunctionArn
}

async function getLambdaLatestVersionArn(client: LambdaClient, functionName: string): Promise<string | undefined> {
const params: ListVersionsByFunctionCommandInput = {
async function checkLambdaFunctionExistance(client: LambdaClient, functionName: string): Promise<boolean> {
const params: GetFunctionCommandInput = {
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 command = new GetFunctionCommand(params)
const result: GetFunctionCommandOutput = await client.send(command)
if (!result.Configuration?.FunctionArn) {
return false
}

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)
return true
}

async function handleFailure(message?: any): Promise<APIGatewayProxyResult> {
Expand Down
45 changes: 17 additions & 28 deletions mgmt-lambda/test/handlers/handleUpdate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import {
LambdaClient,
GetFunctionCommand,
GetFunctionResponse,
ListVersionsByFunctionCommand,
ListVersionsByFunctionResponse,
UpdateFunctionCodeCommand,
} from '@aws-sdk/client-lambda'
import {
Expand All @@ -30,19 +28,10 @@ const settings: DeploymentSettings = {
LambdaFunctionName: 'fingerprint-pro-lambda-function',
}

const existingLambdaVersions: ListVersionsByFunctionResponse = {
Versions: [
{
FunctionName: 'fingerprint-pro-lambda-function',
FunctionArn: 'arn:aws:lambda:us-east-1:1234567890:function:fingerprint-pro-lambda-function:2',
Version: '2',
},
{
FunctionName: 'fingerprint-pro-lambda-function',
FunctionArn: 'arn:aws:lambda:us-east-1:1234567890:function:fingerprint-pro-lambda-function:1',
Version: '1',
},
],
const existingLambda: GetFunctionResponse = {
Configuration: {
FunctionArn: 'arn:aws:lambda:us-east-1:1234567890:function:fingerprint-pro-lambda-function',
},
}

const functionInfo: GetFunctionResponse = {
Expand Down Expand Up @@ -81,7 +70,7 @@ const cloudFrontConfigBeforeUpdate: GetDistributionConfigResult = {
Quantity: 1,
Items: [
{
LambdaFunctionARN: 'arn:aws:lambda:us-east-1:1234567890:function:fingerprint-pro-lambda-function',
LambdaFunctionARN: 'arn:aws:lambda:us-east-1:1234567890:function:fingerprint-pro-lambda-function:1',
EventType: 'origin-request',
IncludeBody: true,
},
Expand Down Expand Up @@ -158,10 +147,10 @@ describe('Handle mgmt-update', () => {

it('basic test', async () => {
lambdaMock
.on(ListVersionsByFunctionCommand, {
.on(GetFunctionCommand, {
FunctionName: settings.LambdaFunctionName,
})
.resolves(existingLambdaVersions)
.resolves(existingLambda)

lambdaMock
.on(GetFunctionCommand, {
Expand Down Expand Up @@ -189,7 +178,7 @@ describe('Handle mgmt-update', () => {
const result = await handleUpdate(lambdaClient, cloudFrontClient, settings)
expect(result.statusCode).toBe(200)

expect(lambdaMock).toHaveReceivedCommandTimes(ListVersionsByFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(GetFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(UpdateFunctionCodeCommand, 1)
expect(cloudFrontMock).toHaveReceivedCommandTimes(GetDistributionConfigCommand, 1)
expect(cloudFrontMock).toHaveReceivedCommandTimes(UpdateDistributionCommand, 1)
Expand All @@ -198,17 +187,17 @@ describe('Handle mgmt-update', () => {

it('No lambda version', async () => {
lambdaMock
.on(ListVersionsByFunctionCommand, {
.on(GetFunctionCommand, {
FunctionName: settings.LambdaFunctionName,
})
.resolves({})

const result = await handleUpdate(lambdaClient, cloudFrontClient, settings)
expect(result.statusCode).toBe(500)
const error = JSON.parse(result.body)['error']
expect(error).toBe('No lambda version')
expect(error).toBe('Lambda function with name fingerprint-pro-lambda-function not found')

expect(lambdaMock).toHaveReceivedCommandTimes(ListVersionsByFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(GetFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(UpdateFunctionCodeCommand, 0)
expect(cloudFrontMock).toHaveReceivedCommandTimes(GetDistributionConfigCommand, 0)
expect(cloudFrontMock).toHaveReceivedCommandTimes(UpdateDistributionCommand, 0)
Expand All @@ -217,10 +206,10 @@ describe('Handle mgmt-update', () => {

it('CloudFront has no fpjs cache behavior', async () => {
lambdaMock
.on(ListVersionsByFunctionCommand, {
.on(GetFunctionCommand, {
FunctionName: settings.LambdaFunctionName,
})
.resolves(existingLambdaVersions)
.resolves(existingLambda)

lambdaMock
.on(GetFunctionCommand, {
Expand Down Expand Up @@ -286,7 +275,7 @@ describe('Handle mgmt-update', () => {
const error = JSON.parse(result.body)['error']
expect(error).toBe('Cache behavior not found')

expect(lambdaMock).toHaveReceivedCommandTimes(ListVersionsByFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(GetFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(UpdateFunctionCodeCommand, 1)
expect(cloudFrontMock).toHaveReceivedCommandTimes(GetDistributionConfigCommand, 1)
expect(cloudFrontMock).toHaveReceivedCommandTimes(UpdateDistributionCommand, 0)
Expand All @@ -295,10 +284,10 @@ describe('Handle mgmt-update', () => {

it('CloudFront cache behavior without lambda association', async () => {
lambdaMock
.on(ListVersionsByFunctionCommand, {
.on(GetFunctionCommand, {
FunctionName: settings.LambdaFunctionName,
})
.resolves(existingLambdaVersions)
.resolves(existingLambda)

lambdaMock
.on(GetFunctionCommand, {
Expand Down Expand Up @@ -354,7 +343,7 @@ describe('Handle mgmt-update', () => {
const error = JSON.parse(result.body)['error']
expect(error).toBe('Lambda function association not found')

expect(lambdaMock).toHaveReceivedCommandTimes(ListVersionsByFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(GetFunctionCommand, 1)
expect(lambdaMock).toHaveReceivedCommandTimes(UpdateFunctionCodeCommand, 1)
expect(cloudFrontMock).toHaveReceivedCommandTimes(GetDistributionConfigCommand, 1)
expect(cloudFrontMock).toHaveReceivedCommandTimes(UpdateDistributionCommand, 0)
Expand Down

0 comments on commit 403680c

Please sign in to comment.