Skip to content

Commit

Permalink
Stop resource-metadata from failing when it has trouble collecting me…
Browse files Browse the repository at this point in the history
…tadata of some lambda functions.
  • Loading branch information
RafalSumislawski committed Dec 13, 2023
1 parent 9614436 commit 49b177a
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 25 deletions.
3 changes: 3 additions & 0 deletions src/resource-metadata/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## resource-metadata

### 1.2.6 / 13.12.2023
* [Change] The function will not fail when it can't collect metadata of some lambda function

### 1.2.5 / 7.12.2023
* [Update] Add filtering of Lambda functions.

Expand Down
11 changes: 11 additions & 0 deletions src/resource-metadata/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,15 @@ export const traverse = async (array, f) => {
results.push(await f(array[i], i));
}
return results;
}

export const flatTraverse = async (array, f) => {
const results = [];
for (var i = 0; i < array.length; i++) {
let result = await f(array[i], i)
if (result) {
results.push(result);
}
}
return results;
}
61 changes: 38 additions & 23 deletions src/resource-metadata/lambda.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from 'assert'
import { paginateListFunctions, LambdaClient, GetFunctionCommand, ListAliasesCommand, GetPolicyCommand, ListVersionsByFunctionCommand, ListEventSourceMappingsCommand } from '@aws-sdk/client-lambda'
import { ResourceGroupsTaggingAPIClient, paginateGetResources } from '@aws-sdk/client-resource-groups-tagging-api';
import { schemaUrl, extractArchitecture, intAttr, stringAttr, traverse } from './common.js'
import { schemaUrl, extractArchitecture, intAttr, stringAttr, traverse, flatTraverse } from './common.js'

const validateAndExtractConfiguration = () => {
assert(process.env.LATEST_VERSIONS_PER_FUNCTION, "LATEST_VERSIONS_PER_FUNCTION env var missing!")
Expand Down Expand Up @@ -69,32 +69,40 @@ const collectFunctionsArnsMatchingTagFilters = async () => {
}

const collectFunctionAndAliasResources = async (listOfFunctions) => {
const results = await traverse(listOfFunctions, async (lambdaFunctionVersionLatest, index) => {
const results = await flatTraverse(listOfFunctions, async (lambdaFunctionVersionLatest, index) => {
const functionName = lambdaFunctionVersionLatest.FunctionName
try {
const lambdaFunction = await lambdaClient.send(new GetFunctionCommand({ FunctionName: functionName }))
const functionResource = makeLambdaFunctionResource(lambdaFunction)

const lambdaFunction = await lambdaClient.send(new GetFunctionCommand({ FunctionName: functionName }))
const functionResource = makeLambdaFunctionResource(lambdaFunction)

const aliases = collectAliases
? (await lambdaClient.send(new ListAliasesCommand({ FunctionName: functionName })))?.Aliases
: []
const aliasResources = aliases.map(alias => makeAliasResource(functionName, alias))
const aliases = collectAliases
? (await lambdaClient.send(new ListAliasesCommand({ FunctionName: functionName })))?.Aliases
: []
const aliasResources = aliases.map(alias => makeAliasResource(functionName, alias))

const versions = latestVersionsPerFunction > 0
? (await lambdaClient.send(new ListVersionsByFunctionCommand({ FunctionName: functionName }))).Versions
: [lambdaFunctionVersionLatest]
const versions = latestVersionsPerFunction > 0
? (await lambdaClient.send(new ListVersionsByFunctionCommand({ FunctionName: functionName }))).Versions
: [lambdaFunctionVersionLatest]

const versionsToCollect = versions.filter((version, index) => {
return (index <= latestVersionsPerFunction) // Is either $LATEST or one of the latestVersionsPerFunction latest released versions // This relies on the fact that AWS returns the functions in latest -> oldest order
|| (aliases.some(alias => version.Version === alias.FunctionVersion)) // has an alias
})
const versionsToCollect = versions.filter((version, index) => {
return (index <= latestVersionsPerFunction) // Is either $LATEST or one of the latestVersionsPerFunction latest released versions // This relies on the fact that AWS returns the functions in latest -> oldest order
|| (aliases.some(alias => version.Version === alias.FunctionVersion)) // has an alias
})

console.debug(`Function (${index + 1}/${listOfFunctions.length}): ${JSON.stringify(functionResource)}`)
aliasResources.forEach(a => console.debug(`Alias: ${JSON.stringify(a)}`))
console.debug(`Function (${index + 1}/${listOfFunctions.length}): ${JSON.stringify(functionResource)}`)
aliasResources.forEach(a => console.debug(`Alias: ${JSON.stringify(a)}`))

return { functionResource, aliasResources, versionsToCollect }
return { functionResource, aliasResources, versionsToCollect }
} catch (error) {
console.warn(`Failed to collect metadata of ${functionName}: `, error.stack)
}
})

if (listOfFunctions.length > 0 && results.length == 0) {
console.error("Failed to collect metadata of any lambda function.")
throw "Failed to collect metadata of any lambda function."
}

return {
functionResources: results.map(x => x.functionResource),
aliasResources: results.flatMap(x => x.aliasResources),
Expand All @@ -108,7 +116,12 @@ const collectFunctionVersionResources = async (versionsToCollect) =>
? lambdaFunctionVersion.FunctionName
: `${lambdaFunctionVersion.FunctionName}:${lambdaFunctionVersion.Version}`

const eventSourceMappings = await lambdaClient.send(new ListEventSourceMappingsCommand({ FunctionName: functionNameForRequests }))
let eventSourceMappings = null
try {
eventSourceMappings = await lambdaClient.send(new ListEventSourceMappingsCommand({ FunctionName: functionNameForRequests }))
} catch (error) {
console.warn(`Failed to collect event source mappings of ${functionNameForRequests}: `, error.stack)
}
let maybePolicy = null
try {
maybePolicy = await lambdaClient.send(new GetPolicyCommand({ FunctionName: functionNameForRequests }))
Expand Down Expand Up @@ -193,9 +206,11 @@ const makeLambdaFunctionVersionResource = (fv, eventSourceMappings, maybePolicy)
})
}

eventSourceMappings.EventSourceMappings.forEach((eventSource, index) => {
attributes.push(stringAttr(`lambda.event_source.${index}.arn`, eventSource.EventSourceArn))
})
if (eventSourceMappings && eventSourceMappings.EventSourceMappings) {
eventSourceMappings.EventSourceMappings.forEach((eventSource, index) => {
attributes.push(stringAttr(`lambda.event_source.${index}.arn`, eventSource.EventSourceArn))
})
}

if (maybePolicy) {
attributes.push(stringAttr("lambda.policy", maybePolicy.Policy))
Expand Down
2 changes: 1 addition & 1 deletion src/resource-metadata/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "coralogix-resource-tags",
"title": "AWS Resource Tags Lambda function for Coralogix",
"version": "1.2.5",
"version": "1.2.6",
"description": "AWS Lambda function to send AWS resource tags to Coralogix",
"homepage": "https://coralogix.com",
"license": "Apache-2.0",
Expand Down
2 changes: 1 addition & 1 deletion src/resource-metadata/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Metadata:
- coralogix
- metadata
HomePageUrl: https://coralogix.com
SemanticVersion: 1.2.5
SemanticVersion: 1.2.6
SourceCodeUrl: https://github.com/coralogix/coralogix-aws-serverless
AWS::CloudFormation::Interface:
ParameterGroups:
Expand Down

0 comments on commit 49b177a

Please sign in to comment.