Skip to content

Commit bee3198

Browse files
Fix compatibility with aws-cdk >= 2.167.0
2 parents 3704bb4 + 64018ed commit bee3198

File tree

3 files changed

+67
-25
lines changed

3 files changed

+67
-25
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ $ awslocal sns list-topics
7777

7878
## Change Log
7979

80+
* 2.19.0: Add support for aws-cdk versions >= `2.167.0`
8081
* 2.18.1: Throw better exception if `aws-cdk` not found
8182
* 2.18.0: Add support for AWS_ENDPOINT_URL, USE_SSL, and BUCKET_MARKER_LOCAL configurations
8283
* 2.17.0: Fix IPv4 fallback check to prevent IPv6 connection issue with `localhost` on macOS

bin/cdklocal

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const getLocalHost = async () => {
4242
// Issue: https://github.com/localstack/aws-cdk-local/issues/78
4343
if (hostname === "localhost") {
4444
try {
45-
const options = { host: hostname, port: EDGE_PORT };
45+
const options = {host: hostname, port: EDGE_PORT};
4646
await checkTCPConnection(options);
4747
} catch (e) {
4848
hostname = "127.0.0.1";
@@ -131,14 +131,15 @@ const getTemplateBody = (params) => {
131131
// small import util function
132132

133133
const modulePrefix = "aws-cdk/node_modules";
134-
const importLib = function importLib (libPath) {
134+
const importLib = function importLib(libPath) {
135135
try {
136136
return require(path.join(modulePrefix, libPath));
137137
} catch (exc) {
138138
return require(path.join(libPath));
139139
}
140140
};
141141

142+
// this isn't doing anything for current versions (e.g. 2.167.1)
142143
const setSdkOptions = async (options, setHttpOptions) => {
143144
if (!useLocal(options)) {
144145
return;
@@ -155,10 +156,13 @@ const setSdkOptions = async (options, setHttpOptions) => {
155156
const patchProviderCredentials = (provider) => {
156157
const origConstr = provider.SdkProvider.withAwsCliCompatibleDefaults;
157158
provider.SdkProvider.withAwsCliCompatibleDefaults = async (options = {}) => {
158-
await setSdkOptions(options, true);
159+
const localEndpoint = await getLocalEndpoint();
160+
await setSdkOptions(options, true); // legacy
159161
const result = await origConstr(options);
160-
result.sdkOptions = result.sdkOptions || {};
161-
await setSdkOptions(result.sdkOptions);
162+
result.sdkOptions = result.sdkOptions || {}; // legacy
163+
await setSdkOptions(result.sdkOptions); // legacy
164+
result.requestHandler.endpoint = localEndpoint;
165+
result.requestHandler.forcePathStyle = true;
162166
return result;
163167
};
164168

@@ -172,7 +176,7 @@ const patchCdkToolkit = (CdkToolkit) => {
172176
const CdkToolkitClass = CdkToolkit.ToolkitInfo || CdkToolkit;
173177
getMethods(CdkToolkitClass.prototype).forEach((meth) => {
174178
const original = CdkToolkitClass.prototype[meth];
175-
CdkToolkitClass.prototype[meth] = async function methFunc (...args) {
179+
CdkToolkitClass.prototype[meth] = async function methFunc(...args) {
176180
await setSdkOptions(this.props.sdkProvider.sdkOptions);
177181
return original.bind(this).apply(this, args);
178182
};
@@ -181,14 +185,14 @@ const patchCdkToolkit = (CdkToolkit) => {
181185

182186
const patchCurrentAccount = (SDK) => {
183187
const currentAccountOrig = SDK.prototype.currentAccount;
184-
SDK.prototype.currentAccount = async function currentAccount () {
188+
SDK.prototype.currentAccount = async function currentAccount() {
185189
const {config} = this;
186190
await setSdkOptions(config);
187191
return currentAccountOrig.bind(this)();
188192
};
189193

190194
const forceCredentialRetrievalOrig = SDK.prototype.forceCredentialRetrieval;
191-
SDK.prototype.forceCredentialRetrieval = function forceCredentialRetrieval () {
195+
SDK.prototype.forceCredentialRetrieval = function forceCredentialRetrieval() {
192196
if (!this._credentials.getPromise) {
193197
this._credentials.getPromise = () => this._credentials;
194198
}
@@ -201,9 +205,9 @@ const patchToolkitInfo = (ToolkitInfo) => {
201205
BUCKET_NAME_OUTPUT, BUCKET_DOMAIN_NAME_OUTPUT
202206
} = require("aws-cdk/lib/api/bootstrap/bootstrap-props");
203207

204-
const setBucketUrl = function setBucketUrl (object) {
208+
const setBucketUrl = function setBucketUrl(object) {
205209
Object.defineProperty(object, "bucketUrl", {
206-
async get () {
210+
async get() {
207211
const bucket = this.requireOutput(BUCKET_NAME_OUTPUT);
208212
const domain = this.requireOutput(BUCKET_DOMAIN_NAME_OUTPUT) || await getLocalHost();
209213
return `https://${domain.replace(`${bucket}.`, "")}:${EDGE_PORT}/${bucket}`;
@@ -236,19 +240,14 @@ const patchLambdaMounting = (CdkToolkit) => {
236240
// modify asset paths to enable local Lambda code mounting
237241

238242
const lookupLambdaForAsset = (template, paramName) => {
239-
const result = Object.keys(template.Resources).
240-
map((key) => template.Resources[key]).
241-
filter((res) => res.Type === "AWS::Lambda::Function").
242-
filter((res) => JSON.stringify(res.Properties.Code.S3Key).includes(paramName));
243+
const result = Object.keys(template.Resources).map((key) => template.Resources[key]).filter((res) => res.Type === "AWS::Lambda::Function").filter((res) => JSON.stringify(res.Properties.Code.S3Key).includes(paramName));
243244
const props = result[0].Properties;
244245
const funcName = props.FunctionName;
245246
if (funcName) {
246247
return funcName;
247248
}
248249
const attributes = ["Handler", "Runtime", "Description", "Timeout", "MemorySize", "Environment"];
249-
const valueToHash = attributes.map((attr) => props[attr]).
250-
map((val) => typeof val === "object" ? JSON.stringify(diff.canonicalize(val)) : val ? val : "").
251-
join("|");
250+
const valueToHash = attributes.map((attr) => props[attr]).map((val) => typeof val === "object" ? JSON.stringify(diff.canonicalize(val)) : val ? val : "").join("|");
252251
return md5(valueToHash);
253252
};
254253

@@ -292,13 +291,13 @@ const patchLambdaMounting = (CdkToolkit) => {
292291
// symlink local Lambda assets if "cdklocal deploy" is called with LAMBDA_MOUNT_CODE=1
293292

294293
const deployStackOrig = deployStackMod.deployStack;
295-
deployStackMod.deployStack = function deployStack (options) {
294+
deployStackMod.deployStack = function deployStack(options) {
296295
options.sdk.cloudFormationOrig = options.sdk.cloudFormationOrig || options.sdk.cloudFormation;
297296
const state = {};
298297
options.sdk.cloudFormation = () => state.instance;
299298
const cfn = state.instance = options.sdk.cloudFormationOrig();
300299
cfn.createChangeSetOrig = cfn.createChangeSetOrig || cfn.createChangeSet;
301-
const createChangeSetAsync = async function createChangeSetAsync (params) {
300+
const createChangeSetAsync = async function createChangeSetAsync(params) {
302301
if (LAMBDA_MOUNT_CODE) {
303302
const template = deserializeStructure(await getTemplateBody(params));
304303
symlinkLambdaAssets(template, params.Parameters);
@@ -315,7 +314,7 @@ const patchLambdaMounting = (CdkToolkit) => {
315314
const {FileAssetHandler} = importLib("cdk-assets/lib/private/handlers/files");
316315

317316
const handlerPublish = FileAssetHandler.prototype.publish;
318-
FileAssetHandler.prototype.publish = function publish () {
317+
FileAssetHandler.prototype.publish = function publish() {
319318
if (LAMBDA_MOUNT_CODE && this.asset.destination && this.asset.source) {
320319
if (this.asset.source.packaging === "zip") {
321320
// skip uploading this asset - should get mounted via `__file__` into the Lambda container later on
@@ -328,7 +327,7 @@ const patchLambdaMounting = (CdkToolkit) => {
328327
// symlink local Lambda assets if "cdklocal synth" is called with LAMBDA_MOUNT_CODE=1
329328

330329
const assemblyOrig = CdkToolkit.prototype.assembly;
331-
CdkToolkit.prototype.assembly = async function assembly () {
330+
CdkToolkit.prototype.assembly = async function assembly() {
332331
const result = await assemblyOrig.bind(this)();
333332
if (LAMBDA_MOUNT_CODE) {
334333
result.assembly.artifacts.forEach((art) => {
@@ -351,7 +350,48 @@ const isEsbuildBundle = () => {
351350
}
352351
};
353352

353+
354+
const patchSdk = (SDK, localEndpoint) => {
355+
getMethods(SDK.prototype).forEach((methodName) => {
356+
if (typeof SDK.prototype[methodName] === 'function') {
357+
const original = SDK.prototype[methodName];
358+
SDK.prototype[methodName] = function methFunc(...args) {
359+
this.config.endpoint = localEndpoint;
360+
this.config.forcePathStyle = true;
361+
return original.apply(this, args);
362+
};
363+
}
364+
});
365+
};
366+
367+
let sdkOverwritten = false;
368+
const patchSdkProvider = (provider, SDK) => {
369+
getMethods(provider.SdkProvider.prototype).forEach((methodName) => {
370+
if (typeof provider.SdkProvider.prototype[methodName] === 'function') {
371+
const original = provider.SdkProvider.prototype[methodName];
372+
provider.SdkProvider.prototype[methodName] = async function methFunc(...args) {
373+
const localEndpoint = await getLocalEndpoint();
374+
375+
if (!sdkOverwritten) {
376+
// the goal is to support `SdkProvider.withAssumedRole`
377+
// since it instantiates a different client (i.e. not from the SDK class)
378+
this.requestHandler.endpoint = localEndpoint;
379+
this.requestHandler.forcePathStyle = true;
380+
// patch SDK class methods (mostly clients) to make sure the config that is created in the constructor
381+
// is updated with the correct configuration
382+
patchSdk(SDK, localEndpoint);
383+
sdkOverwritten = true;
384+
}
385+
return await original.apply(this, args);
386+
};
387+
}
388+
}
389+
);
390+
};
391+
354392
const applyPatches = (provider, CdkToolkit, SDK, ToolkitInfo, patchAssets = true) => {
393+
patchSdkProvider(provider, SDK);
394+
// TODO: a lot of the patches are not really needed for newer versions
355395
patchProviderCredentials(provider);
356396
patchCdkToolkit(CdkToolkit);
357397
patchCurrentAccount(SDK);
@@ -366,7 +406,7 @@ const patchPre_2_14 = () => {
366406
var provider = null;
367407
try {
368408
provider = require("aws-cdk/lib/api/aws-auth");
369-
} catch(e) {
409+
} catch (e) {
370410
if (e.code == "MODULE_NOT_FOUND") {
371411
console.log(e);
372412
console.error("`aws-cdk` module NOT found! Have you tried adding it to your `NODE_PATH`?");
@@ -386,7 +426,7 @@ const patchPost_2_14 = () => {
386426
var lib = null;
387427
try {
388428
lib = require("aws-cdk/lib");
389-
} catch(e) {
429+
} catch (e) {
390430
if (e.code == "MODULE_NOT_FOUND") {
391431
console.log(e);
392432
console.log("`aws-cdk` module NOT found! Have you tried to add it to your `NODE_PATH`?");

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"name": "aws-cdk-local",
33
"description": "CDK Toolkit for use with LocalStack",
4-
"version": "2.18.1",
4+
"version": "2.19.0",
55
"bin": {
66
"cdklocal": "bin/cdklocal"
77
},
88
"scripts": {
9-
"lint": "eslint bin/cdklocal"
9+
"lint": "eslint bin/cdklocal",
10+
"format": "eslint --fix bin/cdklocal"
1011
},
1112
"author": {
1213
"name": "LocalStack",

0 commit comments

Comments
 (0)