Skip to content

Commit

Permalink
feat(toolkit): allow to pass build args to docker build (#2604)
Browse files Browse the repository at this point in the history
  • Loading branch information
jogold authored and rix0rrr committed May 22, 2019
1 parent 96c2842 commit c51596e
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 5 deletions.
16 changes: 14 additions & 2 deletions packages/@aws-cdk/assets-docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,20 @@ This will instruct the toolkit to build a Docker image from `my-image`, push it
to an AWS ECR repository and wire the name of the repository as CloudFormation
parameters to your stack.

Use `asset.imageUri` can be used to reference the image (it includes both the
ECR image URL and tag.
Use `asset.imageUri` to reference the image (it includes both the ECR image URL
and tag.

You can optionally pass build args to the `docker build` command by specifying
the `buildArgs` property:

```typescript
const asset = new DockerImageAsset(this, 'MyBuildImage', {
directory: path.join(__dirname, 'my-image'),
buildArgs: {
HTTP_PROXY: 'http://10.20.30.2:1234'
}
});
```

### Pull Permissions

Expand Down
8 changes: 8 additions & 0 deletions packages/@aws-cdk/assets-docker/lib/image-asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ export interface DockerImageAssetProps {
* @default automatically derived from the asset's ID.
*/
readonly repositoryName?: string;

/**
* Build args to pass to the `docker build` command
*
* @default no build args are passed
*/
readonly buildArgs?: { [key: string]: string };
}

/**
Expand Down Expand Up @@ -75,6 +82,7 @@ export class DockerImageAsset extends cdk.Construct {
id: this.node.uniqueId,
imageNameParameter: imageNameParameter.logicalId,
repositoryName: props.repositoryName,
buildArgs: props.buildArgs
};

this.node.addMetadata(cxapi.ASSET_METADATA, asset);
Expand Down
18 changes: 18 additions & 0 deletions packages/@aws-cdk/assets-docker/test/test.image-asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@ export = {
test.done();
},

'with build args'(test: Test) {
// GIVEN
const stack = new cdk.Stack();

// WHEN
const asset = new DockerImageAsset(stack, 'Image', {
directory: path.join(__dirname, 'demo-image'),
buildArgs: {
a: 'b'
}
});

// THEN
const assetMetadata = asset.node.metadata.find(({ type }) => type === 'aws:cdk:asset');
test.deepEqual(assetMetadata && assetMetadata.data.buildArgs, { a: 'b' });
test.done();
},

'asset.repository.grantPull can be used to grant a principal permissions to use the image'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
Expand Down
12 changes: 11 additions & 1 deletion packages/@aws-cdk/aws-ecs/lib/images/asset-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ export interface AssetImageProps {
* The directory where the Dockerfile is stored
*/
readonly directory: string;

/**
* Build args to pass to the `docker build` command
*
* @default no build args are passed
*/
readonly buildArgs?: { [key: string]: string };
}

/**
Expand All @@ -19,7 +26,10 @@ export class AssetImage extends ContainerImage {

constructor(scope: cdk.Construct, id: string, props: AssetImageProps) {
super();
this.asset = new DockerImageAsset(scope, id, { directory: props.directory });
this.asset = new DockerImageAsset(scope, id, {
directory: props.directory,
buildArgs: props.buildArgs,
});
}

public bind(containerDefinition: ContainerDefinition): void {
Expand Down
9 changes: 8 additions & 1 deletion packages/@aws-cdk/cx-api/lib/metadata/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,16 @@ export interface ContainerImageAssetMetadataEntry {
* Note, this is only the repository name, without the registry and
* the tag parts.
*
* * @default automatically derived from the asset's ID.
* @default automatically derived from the asset's ID.
*/
readonly repositoryName?: string;

/**
* Build args to pass to the `docker build` command
*
* @default no build args are passed
*/
readonly buildArgs?: { [key: string]: string };
}

export type AssetMetadataEntry = FileAssetMetadataEntry | ContainerImageAssetMetadataEntry;
2 changes: 2 additions & 0 deletions packages/aws-cdk/lib/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ export async function prepareContainerAsset(asset: ContainerImageAssetMetadataEn

const baseCommand = ['docker',
'build',
...Object.entries(asset.buildArgs || {}).map(([k, v]) => `--build-arg ${k}=${v}`), // Pass build args if any
'--quiet',
asset.path];

const command = ci
? [...baseCommand, '--cache-from', latest] // This does not fail if latest is not available
: baseCommand;
Expand Down
48 changes: 47 additions & 1 deletion packages/aws-cdk/test/test.docker.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import cxapi = require('@aws-cdk/cx-api');
import { Test } from 'nodeunit';
import sinon = require('sinon');
import { ToolkitInfo } from '../lib';
import { prepareContainerAsset } from '../lib/docker';
import os = require('../lib/os');
import { MockSDK } from './util/mock-sdk';

export = {
Expand Down Expand Up @@ -51,4 +53,48 @@ export = {

test.done();
},
};

async 'passes the correct args to docker build'(test: Test) {
// GIVEN
const toolkit = new ToolkitInfo({
sdk: new MockSDK(),
bucketName: 'BUCKET_NAME',
bucketEndpoint: 'BUCKET_ENDPOINT',
environment: { name: 'env', account: '1234', region: 'abc' }
});

const prepareEcrRepositoryStub = sinon.stub(toolkit, 'prepareEcrRepository').resolves({
repositoryUri: 'uri',
repositoryName: 'name'
});

const shellStub = sinon.stub(os, 'shell').rejects('STOPTEST');

// WHEN
const asset: cxapi.ContainerImageAssetMetadataEntry = {
id: 'assetId',
imageNameParameter: 'MyParameter',
packaging: 'container-image',
path: '/foo',
repositoryName: 'some-name',
buildArgs: {
a: 'b',
c: 'd'
}
};

try {
await prepareContainerAsset(asset, toolkit, false);
} catch (e) {
if (!/STOPTEST/.test(e.toString())) { throw e; }
}

// THEN
const command = ['docker', 'build', '--build-arg a=b', '--build-arg c=d', '--quiet', '/foo'];
test.ok(shellStub.calledWith(command));

prepareEcrRepositoryStub.restore();
shellStub.restore();
test.done();
}
};

0 comments on commit c51596e

Please sign in to comment.