-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add datasource for AWS Lambda Layers #28251
Open
kayman-mk
wants to merge
86
commits into
renovatebot:main
Choose a base branch
from
Hapag-Lloyd:kayma/add-aws-versioned-arn-datasource
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+722
−9
Open
Changes from 82 commits
Commits
Show all changes
86 commits
Select commit
Hold shift + click to select a range
1e07577
add dummy datasource description for draft pull request only
kayman-mk fa638fe
base implementation
kayman-mk 82652f3
add the code
kayman-mk 7a9a5d0
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 9edb2e0
retrieve layer list from AWS
kayman-mk a6168f2
add tests
kayman-mk f25dad7
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 82f8849
Update lib/modules/datasource/aws-versioned-arn/readme.md
kayman-mk e51647a
reset package manager
kayman-mk 5978e15
Merge remote-tracking branch 'origin/main' into kayma/add-aws-version…
kayman-mk 3ca698d
add aws-sdk lambda
kayman-mk 7b5ed71
add datasource to API
kayman-mk 1162613
add docs
kayman-mk c2ffdc5
files lost by accident
kayman-mk d2b2d07
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 87d1fa0
files lost by accident
kayman-mk 9230bb9
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 4999cc2
Merge branch 'kayma/add-aws-versioned-arn-datasource' of github.com:H…
kayman-mk 4f24402
rename files
kayman-mk 1209738
add tests
kayman-mk e2cfb26
add tests
kayman-mk 5e3dad2
add tests
kayman-mk 6c4a7e0
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk ad2bbbc
fix tests and config
kayman-mk 1dda08d
remove sorting
kayman-mk 2f02403
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 10fbbcd
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 9c61e5d
Merge remote-tracking branch 'renovate/main' into kayma/add-aws-versi…
kayman-mk fe88ea6
add docs
kayman-mk 66fa69e
fix compile error
kayman-mk 4b9e51b
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 02f9af0
merge main
kayman-mk 9240b21
fix review
kayman-mk c34473a
Merge remote-tracking branch 'origin/main' into kayma/add-aws-version…
kayman-mk b41aa9d
fix tests and rename `name` to `arn` (in filter)
kayman-mk 673a5d3
ADD-AWS-VERSIONED-ARN-DATASOURCE
kayman-mk f2d87ee
fix docs
kayman-mk 83d626a
add tests
kayman-mk edf9814
make architecture and runtime optional
kayman-mk cbf0b4e
fix example in readme
kayman-mk afe1dab
simplify regex
kayman-mk f4f9251
fix regex in example
kayman-mk 4515246
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 5c5a961
use customManagers in config
kayman-mk 8d075fd
adding customType to config
kayman-mk 8bd1eef
run prettier
kayman-mk 81b4a5c
fix tests
kayman-mk be3e691
remove unused import
kayman-mk 44b60c3
ADD-AWS-VERSIONED-ARN-DATASOURCE
kayman-mk ff1d7f0
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 5babf77
run prettier
kayman-mk 30e0d37
Merge branch 'kayma/add-aws-versioned-arn-datasource' of https://gith…
kayman-mk c94102d
add tests
kayman-mk 39c7e3e
ADD-AWS-VERSIONED-ARN-DATASOURCE
kayman-mk 592ebd9
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 8cf8382
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 0350e8b
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 579e321
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk e5a42f5
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 46d9fc6
fix pnpm-lock
kayman-mk 93eaf1e
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 2bc07b8
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk 045c1f8
Merge branch 'main' into kayma/add-aws-versioned-arn-datasource
kayman-mk f62203a
inline fixtures
kayman-mk a7198b4
Update lib/modules/datasource/aws-lambda-layer/schema.ts
kayman-mk 1673107
merge main
kayman-mk 1bc7563
add tests
kayman-mk 6d0c583
Merge remote-tracking branch 'origin/main' into kayma/add-aws-version…
kayman-mk 579fd66
update pnpm-lock.yaml
kayman-mk 718c9ff
fix api.ts
kayman-mk a373631
add warning if runtime/architecture not filtered but returned by AWS
kayman-mk ebc0f4c
fix merge conflict in lock file
kayman-mk 41849bc
add tests for logger warning
kayman-mk cc4e844
Update lib/modules/datasource/aws-lambda-layer/index.spec.ts
kayman-mk 3c37e25
fix review
kayman-mk 981cb1b
Merge branch 'kayma/add-aws-versioned-arn-datasource' of https://gith…
kayman-mk aee4443
lock file
kayman-mk 08def38
lock file
kayman-mk 7d84a21
fix tests
kayman-mk bf886ff
fix logger
kayman-mk 0641910
update package lock
kayman-mk 44b5529
fix test
kayman-mk 902c592
fix prettier
kayman-mk c81eb0d
log error as error and ignore for tests
kayman-mk 645d5bc
run prettier
kayman-mk df54fb4
istanbul ignore if
kayman-mk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,329 @@ | ||
import type { | ||
LayerVersionsListItem, | ||
ListLayerVersionsCommandOutput} from '@aws-sdk/client-lambda'; | ||
import { | ||
LambdaClient, | ||
ListLayerVersionsCommand | ||
} from '@aws-sdk/client-lambda'; | ||
import { mockClient } from 'aws-sdk-client-mock'; | ||
import { getPkgReleases } from '..'; | ||
import { logger } from '../../../logger'; | ||
import { AwsLambdaLayerDataSource } from '.'; | ||
|
||
const datasource = AwsLambdaLayerDataSource.id; | ||
|
||
/** | ||
* Testdata for mock implementation of LambdaClient | ||
* layer1 to layer3 from oldest to newest | ||
*/ | ||
const layer1: LayerVersionsListItem = { | ||
Version: 1, | ||
CreatedDate: '2021-01-10T00:00:00.000Z', | ||
LayerVersionArn: 'arn:aws:lambda:us-east-1:123456789012:layer:my-layer:3', | ||
}; | ||
|
||
const layer2: LayerVersionsListItem = { | ||
Version: 2, | ||
CreatedDate: '2021-02-05T00:00:00.000Z', | ||
LayerVersionArn: 'arn:aws:lambda:us-east-1:123456789012:layer:my-layer:2', | ||
}; | ||
|
||
const layer3: LayerVersionsListItem = { | ||
Version: 3, | ||
CreatedDate: '2021-03-01T00:00:00.000Z', | ||
LayerVersionArn: 'arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1', | ||
}; | ||
|
||
const layerWithArchitecture: LayerVersionsListItem = { | ||
Version: 3, | ||
CreatedDate: '2021-03-01T00:00:00.000Z', | ||
LayerVersionArn: 'arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1', | ||
CompatibleArchitectures: ['x86_64'], | ||
}; | ||
|
||
const layerWithRuntime: LayerVersionsListItem = { | ||
Version: 3, | ||
CreatedDate: '2021-03-01T00:00:00.000Z', | ||
LayerVersionArn: 'arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1', | ||
CompatibleRuntimes: ['python3.7'], | ||
}; | ||
|
||
const mock3Layers: ListLayerVersionsCommandOutput = { | ||
LayerVersions: [layer1, layer2, layer3], | ||
$metadata: {}, | ||
}; | ||
|
||
const mock1Layer: ListLayerVersionsCommandOutput = { | ||
LayerVersions: [layer3], | ||
$metadata: {}, | ||
}; | ||
|
||
const mockEmpty: ListLayerVersionsCommandOutput = { | ||
LayerVersions: [], | ||
$metadata: {}, | ||
}; | ||
|
||
const mockLayerWithArchitecture: ListLayerVersionsCommandOutput = { | ||
LayerVersions: [layerWithArchitecture], | ||
$metadata: {}, | ||
}; | ||
|
||
const mockLayerWithRuntime: ListLayerVersionsCommandOutput = { | ||
LayerVersions: [layerWithRuntime], | ||
$metadata: {}, | ||
}; | ||
|
||
const lambdaClientMock = mockClient(LambdaClient); | ||
|
||
function mockListLayerVersionsCommandOutput( | ||
result: ListLayerVersionsCommandOutput, | ||
): void { | ||
lambdaClientMock.reset(); | ||
lambdaClientMock.on(ListLayerVersionsCommand).resolves(result); | ||
} | ||
|
||
describe('modules/datasource/aws-lambda-layer/index', () => { | ||
describe('getSortedLambdaLayerVersions', () => { | ||
it('should warn about missing architecture in filter if AWS response contains architecture', async () => { | ||
mockListLayerVersionsCommandOutput(mockLayerWithArchitecture); | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
|
||
await lambdaLayerDatasource.getSortedLambdaLayerVersions( | ||
'arn', | ||
'runtime', | ||
undefined, | ||
); | ||
|
||
expect(logger.warn).toHaveBeenCalledWith( | ||
'AWS returned layers with architecture but the architecture is not set in the filter. You might update to a layer with wrong architecture.', | ||
); | ||
}); | ||
|
||
it('should warn about missing runtime in filter if AWS response contains runtime', async () => { | ||
mockListLayerVersionsCommandOutput(mockLayerWithRuntime); | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
|
||
await lambdaLayerDatasource.getSortedLambdaLayerVersions( | ||
'arn', | ||
undefined, | ||
'architecture', | ||
); | ||
|
||
expect(logger.warn).toHaveBeenCalledWith( | ||
'AWS returned layers with runtime but the runtime is not set in the filter. You might update to a layer with wrong runtime.', | ||
); | ||
}); | ||
|
||
it('should return empty array if no layers are found', async () => { | ||
mockListLayerVersionsCommandOutput(mockEmpty); | ||
const lamdbaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
const res = await lamdbaLayerDatasource.getSortedLambdaLayerVersions( | ||
'xy', | ||
'arm64', | ||
'python3.8', | ||
); | ||
|
||
expect(res).toEqual([]); | ||
}); | ||
|
||
it('should return an empty array if AWS response does not contain LayerVersions', async () => { | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
lambdaClientMock.on(ListLayerVersionsCommand).resolves({ | ||
$metadata: {}, | ||
}); | ||
|
||
const res = await lambdaLayerDatasource.getSortedLambdaLayerVersions( | ||
'xy', | ||
'arm64', | ||
'python3.8', | ||
); | ||
|
||
expect(res).toEqual([]); | ||
}); | ||
|
||
it('should return array with one layer if one layer found', async () => { | ||
mockListLayerVersionsCommandOutput(mock1Layer); | ||
const lamdbaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
const res = await lamdbaLayerDatasource.getSortedLambdaLayerVersions( | ||
'not-relevant', | ||
'not-relevant', | ||
'not-relevant', | ||
); | ||
|
||
expect(res).toEqual([layer3]); | ||
}); | ||
|
||
it('should return array with three layers if three layers found', async () => { | ||
mockListLayerVersionsCommandOutput(mock3Layers); | ||
const lamdbaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
const res = await lamdbaLayerDatasource.getSortedLambdaLayerVersions( | ||
'not-relevant', | ||
'not-relevant', | ||
'not-relevant', | ||
); | ||
|
||
expect(res).toEqual([layer1, layer2, layer3]); | ||
}); | ||
|
||
it('should pass the filters for listLayerVersions when calling the AWS API', async () => { | ||
mockListLayerVersionsCommandOutput(mock3Layers); | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
|
||
await lambdaLayerDatasource.getSortedLambdaLayerVersions( | ||
'arn', | ||
'runtime', | ||
'architecture', | ||
); | ||
|
||
expect(lambdaClientMock.calls()).toHaveLength(1); | ||
|
||
expect(lambdaClientMock.calls()[0].args[0].input).toEqual({ | ||
CompatibleArchitecture: 'architecture', | ||
CompatibleRuntime: 'runtime', | ||
LayerName: 'arn', | ||
}); | ||
}); | ||
|
||
it('should call AWS with no architecture if there is no architecture in the filter', async () => { | ||
mockListLayerVersionsCommandOutput(mock3Layers); | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
|
||
await lambdaLayerDatasource.getSortedLambdaLayerVersions( | ||
'arn', | ||
'runtime', | ||
undefined, | ||
); | ||
|
||
expect(lambdaClientMock.calls()).toHaveLength(1); | ||
|
||
expect(lambdaClientMock.calls()[0].args[0].input).toEqual({ | ||
CompatibleArchitecture: undefined, | ||
CompatibleRuntime: 'runtime', | ||
LayerName: 'arn', | ||
}); | ||
}); | ||
|
||
it('should call AWS with no runtime if there is no runtime in the filter', async () => { | ||
mockListLayerVersionsCommandOutput(mock3Layers); | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
|
||
await lambdaLayerDatasource.getSortedLambdaLayerVersions( | ||
'arn', | ||
undefined, | ||
'python3.8', | ||
); | ||
|
||
expect(lambdaClientMock.calls()).toHaveLength(1); | ||
|
||
expect(lambdaClientMock.calls()[0].args[0].input).toEqual({ | ||
CompatibleArchitecture: 'python3.8', | ||
CompatibleRuntime: undefined, | ||
LayerName: 'arn', | ||
}); | ||
}); | ||
}); | ||
|
||
describe('getReleases', () => { | ||
it('should throw an exception if the filter criteria does not match the schema', async () => { | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
const res = lambdaLayerDatasource.getReleases({ | ||
packageName: '{"invalid": "json"}', | ||
}); | ||
|
||
await expect(res).rejects.toThrow(); | ||
}); | ||
|
||
it('should throw an exception if version is not set in AWS response', async () => { | ||
mockListLayerVersionsCommandOutput({ | ||
LayerVersions: [ | ||
{ | ||
CreatedDate: '2021-01-10T00:00:00.000Z', | ||
LayerVersionArn: | ||
'arn:aws:lambda:us-east-1:123456789012:layer:my-layer:3', | ||
}, | ||
], | ||
$metadata: {}, | ||
}); | ||
const lambdaLayerDatasource = new AwsLambdaLayerDataSource(); | ||
|
||
await expect(() => | ||
lambdaLayerDatasource.getReleases({ | ||
packageName: | ||
'{"arn": "arn:aws:lambda:us-east-1:123456789012:layer:my-layer", "runtime": "python37", "architecture": "x86_64"}', | ||
}), | ||
).rejects.toThrow( | ||
'Version is not set in AWS response for ListLayerVersionsCommand', | ||
); | ||
}); | ||
}); | ||
|
||
describe('integration', () => { | ||
describe('getPkgReleases', () => { | ||
it('should return null if no releases found', async () => { | ||
mockListLayerVersionsCommandOutput(mockEmpty); | ||
|
||
const res = await getPkgReleases({ | ||
datasource, | ||
packageName: | ||
'{"arn": "arn:aws:lambda:us-east-1:123456789012:layer:my-layer", "runtime": "python37", "architecture": "x86_64"}', | ||
}); | ||
|
||
expect(res).toBeNull(); | ||
}); | ||
|
||
it('should return one image', async () => { | ||
mockListLayerVersionsCommandOutput(mock1Layer); | ||
|
||
const res = await getPkgReleases({ | ||
datasource, | ||
packageName: | ||
'{"arn": "arn:aws:lambda:us-east-1:123456789012:layer:my-layer", "runtime": "python37", "architecture": "x86_64"}', | ||
}); | ||
|
||
expect(res).toStrictEqual({ | ||
releases: [ | ||
{ | ||
isDeprecated: false, | ||
version: layer3.Version?.toFixed(0), | ||
newDigest: layer3.LayerVersionArn, | ||
releaseTimestamp: layer3.CreatedDate, | ||
}, | ||
], | ||
}); | ||
}); | ||
|
||
it('should return 3 images', async () => { | ||
mockListLayerVersionsCommandOutput(mock3Layers); | ||
|
||
const res = await getPkgReleases({ | ||
datasource, | ||
packageName: | ||
'{"arn": "arn:aws:lambda:us-east-1:123456789012:layer:my-layer", "runtime": "python37", "architecture": "x86_64"}', | ||
}); | ||
|
||
expect(res).toStrictEqual({ | ||
releases: [ | ||
{ | ||
isDeprecated: false, | ||
version: layer1.Version?.toFixed(0), | ||
newDigest: layer1.LayerVersionArn, | ||
releaseTimestamp: layer1.CreatedDate, | ||
}, | ||
{ | ||
isDeprecated: false, | ||
version: layer2.Version?.toFixed(0), | ||
newDigest: layer2.LayerVersionArn, | ||
releaseTimestamp: layer2.CreatedDate, | ||
}, | ||
{ | ||
isDeprecated: false, | ||
version: layer3.Version?.toFixed(0), | ||
newDigest: layer3.LayerVersionArn, | ||
releaseTimestamp: layer3.CreatedDate, | ||
}, | ||
], | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@viceice Is this assumption correct? If not: how to catch this error?
Looks ugly and I guess there is a better option. Checking the existing source, I didn't find any.