Skip to content

Commit 3a0b358

Browse files
author
Marco Franceschi
authored
Merge pull request #141 from cloudgraphdev/feat/EP-3183
feat: Added more information to lambda service
2 parents 3f673a2 + 624f9c2 commit 3a0b358

6 files changed

Lines changed: 351 additions & 7 deletions

File tree

src/services/iamPolicy/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type awsIamJSONPolicyStatement
3232
action: [String] @search(by: [hash])
3333
condition: [awsIamJSONPolicyCondition]
3434
effect: String @search(by: [hash, regexp])
35+
sid: String @search(by: [hash, regexp])
3536
principal: [awsIamJSONPolicyPrincipal]
3637
resource: [String] @search(by: [hash])
3738
notAction: [String] @search(by: [hash])

src/services/lambda/data.ts

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ import Lambda, {
99
GetFunctionConcurrencyRequest,
1010
GetFunctionConcurrencyResponse,
1111
ReservedConcurrentExecutions,
12-
GetPolicyResponse
12+
GetPolicyResponse,
13+
ListEventSourceMappingsResponse,
14+
EventSourceMappingConfiguration,
15+
ListFunctionEventInvokeConfigsResponse,
16+
FunctionEventInvokeConfig,
17+
Layer
1318
} from 'aws-sdk/clients/lambda'
1419
import { AWSError } from 'aws-sdk/lib/error'
1520
import { Config } from 'aws-sdk/lib/config'
@@ -35,6 +40,9 @@ export interface RawAwsLambdaFunction extends FunctionConfiguration {
3540
Policy?: string
3641
RevisionId?: string
3742
}
43+
EventSourceMappings?: EventSourceMappingConfiguration[]
44+
EventInvokeConfigs?: FunctionEventInvokeConfig[]
45+
Layers?: Layer[]
3846
}
3947

4048
const listFunctionsForRegion = async ({
@@ -137,7 +145,7 @@ const getResourceTags = async (lambda: Lambda, arn: string): Promise<TagMap> =>
137145
}
138146
})
139147

140-
const getLambdaPolicy = async (lambda: Lambda, arn: string): Promise<{ Policy?: string; RevisionId?: string }> =>
148+
const getLambdaPolicy = async (lambda: Lambda, arn: string): Promise<{ Policy?: string; RevisionId?: string }> =>
141149
new Promise(resolve => {
142150
try {
143151
lambda.getPolicy(
@@ -159,6 +167,52 @@ const getResourceTags = async (lambda: Lambda, arn: string): Promise<TagMap> =>
159167
}
160168
})
161169

170+
const getEventSourceMappings = async (lambda: Lambda, arn: string): Promise<EventSourceMappingConfiguration[]> =>
171+
new Promise(resolve => {
172+
try {
173+
lambda.listEventSourceMappings(
174+
{ FunctionName: arn },
175+
(err: AWSError, data: ListEventSourceMappingsResponse) => {
176+
if (err) {
177+
errorLog.generateAwsErrorLog({
178+
functionName: 'lambda:listEventSourceMappings',
179+
err,
180+
})
181+
resolve([])
182+
}
183+
const { EventSourceMappings = [] } = data || {}
184+
185+
resolve(EventSourceMappings)
186+
}
187+
)
188+
} catch (error) {
189+
resolve([])
190+
}
191+
})
192+
193+
const getEventInvokeConfigs = async (lambda: Lambda, name: string): Promise<FunctionEventInvokeConfig[]> =>
194+
new Promise(resolve => {
195+
try {
196+
lambda.listFunctionEventInvokeConfigs(
197+
{ FunctionName: name },
198+
(err: AWSError, data: ListFunctionEventInvokeConfigsResponse) => {
199+
if (err) {
200+
errorLog.generateAwsErrorLog({
201+
functionName: 'lambda:listFunctionEventInvokeConfigs',
202+
err,
203+
})
204+
resolve([])
205+
}
206+
const { FunctionEventInvokeConfigs = [] } = data || {}
207+
208+
resolve(FunctionEventInvokeConfigs)
209+
}
210+
)
211+
} catch (error) {
212+
resolve([])
213+
}
214+
})
215+
162216
export default async ({
163217
regions,
164218
config,
@@ -199,16 +253,22 @@ export default async ({
199253
logger.debug(lt.fetchedLambdas(lambdaData.length))
200254

201255
// get all tags and policy for each Lambda
202-
lambdaData.map(({ FunctionArn: arn, region }, idx) => {
256+
lambdaData.map(({ FunctionArn: arn, region, FunctionName: name, Layers }, idx) => {
203257
const lambda = new Lambda({ ...config, region, endpoint })
204-
const tagsAndPolicyPromise = new Promise<void>(async resolveData => {
258+
259+
const additionalMetadataPromise = new Promise<void>(async resolveData => {
205260
const envTags: TagMap = await getResourceTags(lambda, arn)
206261
lambdaData[idx].Tags = envTags
207262
const policy = await getLambdaPolicy(lambda, arn)
208263
lambdaData[idx].PolicyData = policy
264+
const eventSourceMappings = await getEventSourceMappings(lambda, arn)
265+
lambdaData[idx].EventSourceMappings = eventSourceMappings
266+
const eventInvokeConfigs = await getEventInvokeConfigs(lambda, name)
267+
lambdaData[idx].EventInvokeConfigs = eventInvokeConfigs
268+
lambdaData[idx].Layers = Layers
209269
resolveData()
210270
})
211-
tagsPromises.push(tagsAndPolicyPromise)
271+
tagsPromises.push(additionalMetadataPromise)
212272
})
213273

214274
logger.debug(lt.gettingLambdaTags)

src/services/lambda/format.ts

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { generateUniqueId } from '@cloudgraph/sdk'
12
import isEmpty from 'lodash/isEmpty'
23
import t from '../../properties/translations'
3-
import { AwsLambda } from '../../types/generated'
4+
import { AwsLambda, AwsLambdaEventInvokeConfig, AwsLambdaEventSourceMappings, AwsLambdaLayerVersion } from '../../types/generated'
45
import { formatTagsFromMap, formatIamJsonPolicy } from '../../utils/format'
56
import { RawAwsLambdaFunction } from './data'
7+
import { EventSourceMappingConfiguration, FunctionEventInvokeConfig, Layer } from 'aws-sdk/clients/lambda'
68

79
/**
810
* Lambda
@@ -33,6 +35,9 @@ export default ({
3335
reservedConcurrentExecutions: rawReservedConcurrentExecutions,
3436
VpcConfig: vpcConfig,
3537
PolicyData: { Policy: policy = '', RevisionId: policyRevisionId = '' },
38+
EventSourceMappings: eventSourceMappings = [],
39+
EventInvokeConfigs: eventInvokeConfigs = [],
40+
Layers: layers = []
3641
} = rawData
3742
const environmentVariables = []
3843
const secretNames = [t.pass, t.secret, t.private, t.cert]
@@ -68,10 +73,120 @@ export default ({
6873
securityGroupIds: vpcConfig?.SecurityGroupIds,
6974
}
7075

76+
const formatEventSourceMappings = (
77+
eventSourceMappings?: EventSourceMappingConfiguration[]
78+
): AwsLambdaEventSourceMappings[] => {
79+
return (
80+
eventSourceMappings?.map(e => ({
81+
id: generateUniqueId({
82+
arn,
83+
...e,
84+
}),
85+
uuid: e.UUID,
86+
startingPosition: e.StartingPosition,
87+
batchSize: e.BatchSize,
88+
maximumBatchingWindowInSeconds: e.MaximumBatchingWindowInSeconds,
89+
parallelizationFactor: e.ParallelizationFactor,
90+
eventSourceArn: e.EventSourceArn,
91+
filterCriteria: e.FilterCriteria?.Filters?.map(f => f.Pattern) || [],
92+
functionArn: e.FunctionArn,
93+
lastModified: e.LastModified?.toISOString(),
94+
lastProcessingResult: e.LastProcessingResult,
95+
state: e.State,
96+
stateTransitionReason: e.StateTransitionReason,
97+
destinationConfig: {
98+
id: generateUniqueId({
99+
arn,
100+
...e.DestinationConfig,
101+
102+
}),
103+
OnSuccess: e.DestinationConfig?.OnSuccess?.Destination,
104+
OnFailure: e.DestinationConfig?.OnFailure?.Destination
105+
106+
},
107+
topics: e.Topics,
108+
queues: e.Queues,
109+
maximumRecordAgeInSeconds: e.MaximumRecordAgeInSeconds,
110+
bisectBatchOnFunctionError: e.BisectBatchOnFunctionError,
111+
maximumRetryAttempts: e.MaximumRetryAttempts,
112+
tumblingWindowInSeconds: e.TumblingWindowInSeconds,
113+
functionResponseTypes: e.FunctionResponseTypes,
114+
amazonManagedKafkaEventSourceConfig: {
115+
id: generateUniqueId({
116+
arn,
117+
...e.AmazonManagedKafkaEventSourceConfig
118+
}),
119+
consumerGroupId: e.AmazonManagedKafkaEventSourceConfig?.ConsumerGroupId
120+
},
121+
selfManagedKafkaEventSourceConfig: {
122+
id: generateUniqueId({
123+
arn,
124+
...e.SelfManagedKafkaEventSourceConfig
125+
}),
126+
consumerGroupId: e.SelfManagedKafkaEventSourceConfig?.ConsumerGroupId
127+
}
128+
})) || []
129+
)
130+
}
131+
132+
const formatEventInvokeConfigs = (
133+
eventInvokeConfigs?: FunctionEventInvokeConfig[]
134+
): AwsLambdaEventInvokeConfig[] => {
135+
return (
136+
eventInvokeConfigs?.map(e => ({
137+
id: generateUniqueId({
138+
arn,
139+
...e,
140+
}),
141+
lastModified: e.LastModified?.toISOString(),
142+
functionArn: e.FunctionArn,
143+
maximumRetryAttempts: e.MaximumRetryAttempts,
144+
maximumEventAgeInSeconds: e.MaximumEventAgeInSeconds,
145+
destinationConfig: {
146+
id: generateUniqueId({
147+
arn,
148+
...e.DestinationConfig,
149+
150+
}),
151+
OnSuccess: e.DestinationConfig?.OnSuccess?.Destination,
152+
OnFailure: e.DestinationConfig?.OnFailure?.Destination
153+
}
154+
})) || []
155+
)
156+
}
157+
158+
const formatLayers = (
159+
layers?: Layer[]
160+
): AwsLambdaLayerVersion[] => {
161+
return (
162+
layers?.map(l => {
163+
const arnParts = l.Arn?.split(':')
164+
// get layer name from arn:aws:lambda:_REGION_:_ACCOUNT_ID_:layer:_LAYER_NAME_:_LAYER_VERSION_
165+
const layerName = arnParts[arnParts.length - 2]
166+
return ({
167+
id: generateUniqueId({
168+
arn,
169+
...l,
170+
}),
171+
arn: l.Arn,
172+
name: layerName,
173+
codeSize: l.CodeSize,
174+
signingProfileVersionArn: l.SigningProfileVersionArn,
175+
signingJobArn: l.SigningJobArn,
176+
})
177+
}) || []
178+
)
179+
}
180+
181+
const functionName = arn.split(':').pop()
182+
const functionPolicy = formatIamJsonPolicy(policy)
183+
const policyStatementIds = functionPolicy?.statement?.map(s => s.sid) ?? []
184+
71185
return {
72186
accountId: account,
73187
arn,
74188
region,
189+
name: functionName,
75190
description,
76191
handler,
77192
id: arn,
@@ -88,7 +203,11 @@ export default ({
88203
vpcConfig: formattedVpcConfig,
89204
policyRevisionId,
90205
rawPolicy: policy,
91-
policy: formatIamJsonPolicy(policy),
206+
policy: functionPolicy,
207+
policyStatementIds,
92208
tags: formatTagsFromMap(Tags),
209+
eventSourceMappings: formatEventSourceMappings(eventSourceMappings),
210+
eventInvokeConfigs: formatEventInvokeConfigs(eventInvokeConfigs),
211+
layers: formatLayers(layers)
93212
}
94213
}

src/services/lambda/schema.graphql

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,97 @@
1+
type awsLambdaEventSourceConfig
2+
@generate(
3+
query: { get: false, query: true, aggregate: false }
4+
mutation: { add: false, delete: false }
5+
subscription: false
6+
) {
7+
id: String! @id
8+
consumerGroupId: String @search(by: [hash, regexp])
9+
}
10+
11+
type awsLambdaSourceAccessConfiguration
12+
@generate(
13+
query: { get: false, query: true, aggregate: false }
14+
mutation: { add: false, delete: false }
15+
subscription: false
16+
) {
17+
id: String! @id
18+
type: String @search(by: [hash, regexp])
19+
uri: String @search(by: [hash, regexp])
20+
}
21+
22+
type awsLambdaDestinationConfig
23+
@generate(
24+
query: { get: false, query: true, aggregate: false }
25+
mutation: { add: false, delete: false }
26+
subscription: false
27+
) {
28+
id: String! @id
29+
OnSuccess: String @search(by: [hash, regexp])
30+
OnFailure: String @search(by: [hash, regexp])
31+
}
32+
33+
type awsLambdaEventInvokeConfig
34+
@generate(
35+
query: { get: false, query: true, aggregate: false }
36+
mutation: { add: false, delete: false }
37+
subscription: false
38+
) {
39+
id: String! @id
40+
lastModified: DateTime @search(by: [day])
41+
functionArn: String @search(by: [hash, regexp])
42+
maximumRetryAttempts: Int
43+
maximumEventAgeInSeconds: Int
44+
destinationConfig: awsLambdaDestinationConfig
45+
}
46+
47+
type awsLambdaEventSourceMappings
48+
@generate(
49+
query: { get: false, query: true, aggregate: false }
50+
mutation: { add: false, delete: false }
51+
subscription: false
52+
) {
53+
id: String! @id
54+
uuid: String @search(by: [hash, regexp])
55+
startingPosition: String @search(by: [hash, regexp])
56+
batchSize: Int
57+
maximumBatchingWindowInSeconds: Int
58+
parallelizationFactor: Int
59+
eventSourceArn: String @search(by: [hash, regexp])
60+
filterCriteria: [String] @search(by: [hash, regexp])
61+
functionArn: String @search(by: [hash, regexp])
62+
lastModified: DateTime @search(by: [day])
63+
lastProcessingResult: String @search(by: [hash, regexp])
64+
state: String @search(by: [hash, regexp])
65+
stateTransitionReason: String @search(by: [hash, regexp])
66+
destinationConfig: awsLambdaDestinationConfig
67+
topics: [String] @search(by: [hash, regexp])
68+
queues: [String] @search(by: [hash, regexp])
69+
maximumRecordAgeInSeconds: Int
70+
bisectBatchOnFunctionError: Boolean
71+
maximumRetryAttempts: Int
72+
tumblingWindowInSeconds: Int
73+
functionResponseTypes: [String] @search(by: [hash, regexp])
74+
amazonManagedKafkaEventSourceConfig: awsLambdaEventSourceConfig
75+
selfManagedKafkaEventSourceConfig: awsLambdaEventSourceConfig
76+
}
77+
78+
type awsLambdaLayerVersion
79+
@generate(
80+
query: { get: false, query: true, aggregate: false }
81+
mutation: { add: false, delete: false }
82+
subscription: false
83+
) {
84+
id: String! @id
85+
arn: String @search(by: [hash, regexp])
86+
name: String @search(by: [hash, regexp])
87+
codeSize: Float
88+
signingProfileVersionArn: String @search(by: [hash, regexp])
89+
signingJobArn: String @search(by: [hash, regexp])
90+
}
91+
192
type awsLambda implements awsBaseService @key(fields: "arn") {
293
description: String @search(by: [hash, regexp, fulltext])
94+
name: String @search(by: [hash, regexp])
395
handler: String @search(by: [hash, regexp])
496
kmsKeyArn: String @search(by: [hash, regexp])
597
lastModified: String @search(by: [hash, regexp])
@@ -15,6 +107,10 @@ type awsLambda implements awsBaseService @key(fields: "arn") {
15107
policyRevisionId: String @search(by: [hash, regexp])
16108
rawPolicy: String @search(by: [hash, regexp])
17109
policy: awsIamJSONPolicy
110+
policyStatementIds: [String] @search(by: [hash, regexp])
111+
eventSourceMappings: [awsLambdaEventSourceMappings]
112+
eventInvokeConfigs: [awsLambdaEventInvokeConfig]
113+
layers: [awsLambdaLayerVersion]
18114
tags: [awsRawTag]
19115
kms: [awsKms] @hasInverse(field: lambda)
20116
securityGroups: [awsSecurityGroup] @hasInverse(field: lambda)

0 commit comments

Comments
 (0)