Skip to content

Commit

Permalink
feat(codebuild): add fromEcrRepository to LinuxGpuBuildImage (aws#17170)
Browse files Browse the repository at this point in the history
Resolves aws#16500


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
iRoachie authored and TikiTDO committed Feb 21, 2022
1 parent 0a661dd commit 0970136
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 1 deletion.
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-codebuild/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ new codebuild.Project(this, 'Project', {
})
```

Alternatively, you can reference an image available in an ECR repository using the `LinuxGpuBuildImage.fromEcrRepository(repo[, tag])` method.

## Logs

CodeBuild lets you specify an S3 Bucket, CloudWatch Log Group or both to receive logs from your projects.
Expand Down
16 changes: 16 additions & 0 deletions packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ export class LinuxGpuBuildImage implements IBindableBuildImage {
return new LinuxGpuBuildImage(repositoryName, tag, account);
}


/**
* Returns a GPU image running Linux from an ECR repository.
*
* NOTE: if the repository is external (i.e. imported), then we won't be able to add
* a resource policy statement for it so CodeBuild can pull the image.
*
* @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-ecr.html
*
* @param repository The ECR repository
* @param tag Image tag (default "latest")
*/
public static fromEcrRepository(repository: ecr.IRepository, tag: string = 'latest'): IBuildImage {
return new LinuxGpuBuildImage(repository.repositoryName, tag, repository.env.account);
}

public readonly type = 'LINUX_GPU_CONTAINER';
public readonly defaultComputeType = ComputeType.LARGE;
public readonly imageId: string;
Expand Down
174 changes: 174 additions & 0 deletions packages/@aws-cdk/aws-codebuild/test/linux-gpu-build-image.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { arrayWith, objectLike } from '@aws-cdk/assert-internal';
import '@aws-cdk/assert-internal/jest';
import * as ecr from '@aws-cdk/aws-ecr';
import * as cdk from '@aws-cdk/core';
import * as codebuild from '../lib';

Expand Down Expand Up @@ -58,4 +59,177 @@ describe('Linux GPU build image', () => {
});
});
});

describe('ECR Repository', () => {
test('allows creating a build image from a new ECR repository', () => {
const stack = new cdk.Stack();

const repository = new ecr.Repository(stack, 'my-repo');

new codebuild.Project(stack, 'Project', {
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: { commands: ['ls'] },
},
}),
environment: {
buildImage: codebuild.LinuxGpuBuildImage.fromEcrRepository(repository, 'v1'),
},
});

expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', {
Environment: {
ComputeType: 'BUILD_GENERAL1_LARGE',
Image: {
'Fn::Join': ['', [
{ Ref: 'AWS::AccountId' },
'.dkr.ecr.',
{ Ref: 'AWS::Region' },
'.',
{ Ref: 'AWS::URLSuffix' },
'/',
{ Ref: 'myrepo5DFA62E5' },
':v1',
]],
},
},
});

expect(stack).toHaveResourceLike('AWS::IAM::Policy', {
PolicyDocument: {
Statement: arrayWith(objectLike({
Action: [
'ecr:BatchCheckLayerAvailability',
'ecr:GetDownloadUrlForLayer',
'ecr:BatchGetImage',
],
Resource: {
'Fn::Join': ['', [
'arn:',
{ Ref: 'AWS::Partition' },
':ecr:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':repository/',
{ Ref: 'myrepo5DFA62E5' },
]],
},
})),
},
});
});

test('allows creating a build image from an existing ECR repository', () => {
const stack = new cdk.Stack();

const repository = ecr.Repository.fromRepositoryName(stack, 'my-imported-repo', 'test-repo');

new codebuild.Project(stack, 'Project', {
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: { commands: ['ls'] },
},
}),
environment: {
buildImage: codebuild.LinuxGpuBuildImage.fromEcrRepository(repository),
},
});

expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', {
Environment: {
ComputeType: 'BUILD_GENERAL1_LARGE',
Image: {
'Fn::Join': ['', [
{ Ref: 'AWS::AccountId' },
'.dkr.ecr.',
{ Ref: 'AWS::Region' },
'.',
{ Ref: 'AWS::URLSuffix' },
'/test-repo:latest',
]],
},
},
});

expect(stack).toHaveResourceLike('AWS::IAM::Policy', {
PolicyDocument: {
Statement: arrayWith(objectLike({
Action: [
'ecr:BatchCheckLayerAvailability',
'ecr:GetDownloadUrlForLayer',
'ecr:BatchGetImage',
],
Resource: {
'Fn::Join': ['', [
'arn:',
{ Ref: 'AWS::Partition' },
':ecr:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':repository/test-repo',
]],
},
})),
},
});
});

test('allows creating a build image from an existing cross-account ECR repository', () => {
const stack = new cdk.Stack();

const repository = ecr.Repository.fromRepositoryArn(stack, 'my-cross-acount-repo', 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo');

new codebuild.Project(stack, 'Project', {
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: { commands: ['ls'] },
},
}),
environment: {
buildImage: codebuild.LinuxGpuBuildImage.fromEcrRepository(repository),
},
});

expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', {
Environment: {
ComputeType: 'BUILD_GENERAL1_LARGE',
Image: {
'Fn::Join': ['', [
'585695036304.dkr.ecr.',
{ Ref: 'AWS::Region' },
'.',
{ Ref: 'AWS::URLSuffix' },
'/foo/bar/foo/fooo:latest',
]],
},
},
});

expect(stack).toHaveResourceLike('AWS::IAM::Policy', {
PolicyDocument: {
Statement: arrayWith(objectLike({
Action: [
'ecr:BatchCheckLayerAvailability',
'ecr:GetDownloadUrlForLayer',
'ecr:BatchGetImage',
],
Resource: {
'Fn::Join': ['', [
'arn:',
{ Ref: 'AWS::Partition' },
':ecr:',
{ Ref: 'AWS::Region' },
':585695036304:repository/foo/bar/foo/fooo',
]],
},
})),
},
});
});
});
});
4 changes: 3 additions & 1 deletion packages/@aws-cdk/aws-ecr/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,9 @@ export class Repository extends RepositoryBase {
}
}

return new Import(scope, id);
return new Import(scope, id, {
environmentFromArn: repositoryArn,
});
}

public static fromRepositoryName(scope: Construct, id: string, repositoryName: string): IRepository {
Expand Down

0 comments on commit 0970136

Please sign in to comment.