Skip to content
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

fix(ecr-assets): unable to use one Dockerfile to build multiple images #5705

Merged
merged 8 commits into from
Jan 8, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/@aws-cdk/assets/lib/fs/copy-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,16 @@ export interface CopyOptions {
*/
readonly exclude?: string[];
}

/**
* Options related to calculating source hash.
*/
export interface FingerprintOptions extends CopyOptions {
eladb marked this conversation as resolved.
Show resolved Hide resolved
/**
* Extra information to encode into the fingerprint (e.g. build instructions
* and other inputs)
*
* @default - hash is only based on source content
*/
readonly extra?: string;
}
10 changes: 1 addition & 9 deletions packages/@aws-cdk/assets/lib/fs/fingerprint.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
import { CopyOptions } from './copy-options';
import { FingerprintOptions } from './copy-options';
import { FollowMode } from './follow-mode';
import { shouldExclude, shouldFollow } from './utils';

Expand All @@ -10,14 +10,6 @@ const CTRL_SOH = '\x01';
const CTRL_SOT = '\x02';
const CTRL_ETX = '\x03';

export interface FingerprintOptions extends CopyOptions {
/**
* Extra information to encode into the fingerprint (e.g. build instructions
* and other inputs)
*/
extra?: string;
}

/**
* Produces fingerprint based on the contents of a single file or an entire directory tree.
*
Expand Down
10 changes: 5 additions & 5 deletions packages/@aws-cdk/assets/lib/staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Construct, ISynthesisSession } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import * as fs from 'fs';
import * as path from 'path';
import { copyDirectory, CopyOptions, fingerprint } from './fs';
import { copyDirectory, fingerprint, FingerprintOptions } from './fs';

export interface StagingProps extends CopyOptions {
export interface StagingProps extends FingerprintOptions {
readonly sourcePath: string;
}

Expand Down Expand Up @@ -46,15 +46,15 @@ export class Staging extends Construct {
*/
public readonly sourceHash: string;

private readonly copyOptions: CopyOptions;
private readonly fingerprintOptions: FingerprintOptions;

private readonly relativePath?: string;

constructor(scope: Construct, id: string, props: StagingProps) {
super(scope, id);

this.sourcePath = props.sourcePath;
this.copyOptions = props;
this.fingerprintOptions = props;
this.sourceHash = fingerprint(this.sourcePath, props);

const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
Expand Down Expand Up @@ -84,7 +84,7 @@ export class Staging extends Construct {
fs.copyFileSync(this.sourcePath, targetPath);
} else if (stat.isDirectory()) {
fs.mkdirSync(targetPath);
copyDirectory(this.sourcePath, targetPath, this.copyOptions);
copyDirectory(this.sourcePath, targetPath, this.fingerprintOptions);
} else {
throw new Error(`Unknown file type: ${this.sourcePath}`);
}
Expand Down
17 changes: 17 additions & 0 deletions packages/@aws-cdk/assets/test/test.staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,22 @@ export = {
'tree.json',
]);
test.done();
},

'allow specifying extra data to include in the source hash'(test: Test) {
// GIVEN
const app = new App();
const stack = new Stack(app, 'stack');
const directory = path.join(__dirname, 'fs', 'fixtures', 'test1');

// WHEN
const withoutExtra = new Staging(stack, 'withoutExtra', { sourcePath: directory });
const withExtra = new Staging(stack, 'withExtra', { sourcePath: directory, extra: 'boom' });
eladb marked this conversation as resolved.
Show resolved Hide resolved

// THEN
test.notEqual(withoutExtra.sourceHash, withExtra.sourceHash);
test.deepEqual(withoutExtra.sourceHash, '2f37f937c51e2c191af66acf9b09f548926008ec68c575bd2ee54b6e997c0e00');
test.deepEqual(withExtra.sourceHash, 'c95c915a5722bb9019e2c725d11868e5a619b55f36172f76bcbcaa8bb2d10c5f');
test.done();
}
};
18 changes: 16 additions & 2 deletions packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as fs from 'fs';
import * as path from 'path';
import { AdoptedRepository } from './adopted-repository';

export interface DockerImageAssetProps extends assets.CopyOptions {
export interface DockerImageAssetProps extends assets.FingerprintOptions {
iliapolo marked this conversation as resolved.
Show resolved Hide resolved
/**
* The directory where the Dockerfile is stored
*/
Expand Down Expand Up @@ -93,10 +93,24 @@ export class DockerImageAsset extends Construct implements assets.IAsset {
exclude = [...exclude, ...fs.readFileSync(ignore).toString().split('\n').filter(e => !!e)];
}

// include build context in "extra" so it will impact the hash
const extraHash = new Array<any>();
if (props.extra) { extraHash.push(props.extra); }
if (props.buildArgs) {
extraHash.push({ buildArgs: props.buildArgs });
}
if (props.target) {
extraHash.push({ target: props.target });
}
if (props.file) {
extraHash.push({ file: props.file });
}

eladb marked this conversation as resolved.
Show resolved Hide resolved
const staging = new assets.Staging(this, 'Staging', {
...props,
exclude,
sourcePath: dir
sourcePath: dir,
extra: extraHash.length === 0 ? undefined : extraHash.map(x => JSON.stringify(x)).join('=====')
eladb marked this conversation as resolved.
Show resolved Hide resolved
});

this.sourceHash = staging.sourceHash;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM python:3.6
EXPOSE 8000
WORKDIR /src
ADD . /src
CMD python3 index.py
21 changes: 21 additions & 0 deletions packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,27 @@ export = {
repositoryName: token
}), /Cannot use Token as value of 'repositoryName'/);

test.done();
},

'docker build options are included in the asset id'(test: Test) {
// GIVEN
const stack = new Stack();
const directory = path.join(__dirname, 'demo-image-custom-docker-file');

const asset1 = new DockerImageAsset(stack, 'Asset1', { directory });
const asset2 = new DockerImageAsset(stack, 'Asset2', { directory, file: 'Dockerfile.Custom' });
const asset3 = new DockerImageAsset(stack, 'Asset3', { directory, target: 'NonDefaultTarget' });
const asset4 = new DockerImageAsset(stack, 'Asset4', { directory, buildArgs: { opt1: '123', opt2: 'boom' } });
const asset5 = new DockerImageAsset(stack, 'Asset5', { directory, file: 'Dockerfile.Custom', target: 'NonDefaultTarget' });
const asset6 = new DockerImageAsset(stack, 'Asset6', { directory, extra: 'random-extra' });

test.deepEqual(asset1.sourceHash, 'b84a5001da0f5714e484134e2471213d7e987e22ee6219469029f1779370cc2a');
test.deepEqual(asset2.sourceHash, 'c6568a7946e92a408c60278f70834b901638e71237d470ed1e5e6d707c55c0c9');
test.deepEqual(asset3.sourceHash, '963a5329c170c54bc667fddab8d9cc4cec4bffb65ce3a1f323bb5fbc1d268732');
test.deepEqual(asset4.sourceHash, '0e3eb87273509e0f0d45d67d40fa3080566aa22abd7f976e1ce7ea60a8ccd0a8');
test.deepEqual(asset5.sourceHash, 'd4b1d298bef965fc992008b564d9e4918fd7e489cce3647fa1554f78e5461f37');
test.deepEqual(asset6.sourceHash, 'ee4f6b50c5261a639a4ff775b44fbe578abee3db2742e771f24d6c03b0745a52');
test.done();
}
};