Skip to content

Commit f0e7cee

Browse files
authored
implement usage of aws_endpoint_url (#243)
1 parent 04f71f8 commit f0e7cee

1 file changed

Lines changed: 93 additions & 70 deletions

File tree

src/index.js

Lines changed: 93 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ const TYPESCRIPT_PLUGIN_BUILD_DIR_WEBPACK = '.webpack/service'; //TODO detect fr
2121
const TS_PLUGIN_ESBUILD = 'EsbuildServerlessPlugin'
2222
const TYPESCRIPT_PLUGIN_BUILD_DIR_ESBUILD = '.esbuild/.build'; //TODO detect from esbuild.config.js
2323

24-
// Default edge port to use with host
25-
const DEFAULT_EDGE_PORT = '4566';
24+
// Default AWS endpoint URL
25+
const DEFAULT_AWS_ENDPOINT_URL = "http://localhost:4566";
2626

2727
// Cache hostname to avoid unnecessary connection checks
2828
var resolvedHostname = undefined;
2929

30+
const awsEndpointUrl = process.env.AWS_ENDPOINT_URL || DEFAULT_AWS_ENDPOINT_URL;
31+
3032
class LocalstackPlugin {
3133
constructor(serverless, options) {
3234

@@ -136,17 +138,17 @@ class LocalstackPlugin {
136138
if (this.detectTypescriptPluginType() === TS_PLUGIN_WEBPACK) {
137139
const p = this.serverless.pluginManager.plugins.find((x) => x.constructor.name === TS_PLUGIN_WEBPACK);
138140
if (
139-
this.shouldMountCode() && (
140-
!p ||
141-
!p.serverless ||
142-
!p.serverless.configurationInput ||
143-
!p.serverless.configurationInput.custom ||
144-
!p.serverless.configurationInput.custom.webpack ||
145-
!p.serverless.configurationInput.custom.webpack.keepOutputDirectory
146-
)
141+
this.shouldMountCode() && (
142+
!p ||
143+
!p.serverless ||
144+
!p.serverless.configurationInput ||
145+
!p.serverless.configurationInput.custom ||
146+
!p.serverless.configurationInput.custom.webpack ||
147+
!p.serverless.configurationInput.custom.webpack.keepOutputDirectory
148+
)
147149
) {
148150
throw new Error('When mounting Lambda code, you must retain webpack output directory. '
149-
+ 'Set custom.webpack.keepOutputDirectory to true.');
151+
+ 'Set custom.webpack.keepOutputDirectory to true.');
150152
}
151153
}
152154
}
@@ -158,7 +160,7 @@ class LocalstackPlugin {
158160
addHookInFirstPosition(eventName, hookFunction) {
159161
this.serverless.pluginManager.hooks[eventName] = this.serverless.pluginManager.hooks[eventName] || [];
160162
this.serverless.pluginManager.hooks[eventName].unshift(
161-
{ pluginName: 'LocalstackPlugin', hook: hookFunction.bind(this, eventName) });
163+
{ pluginName: 'LocalstackPlugin', hook: hookFunction.bind(this, eventName) });
162164
}
163165

164166
activatePlugin(preHooks) {
@@ -241,11 +243,11 @@ class LocalstackPlugin {
241243
this.getStageVariable();
242244

243245
return this.startLocalStack().then(
244-
() => {
246+
() => {
245247
this.patchServerlessSecrets();
246248
this.patchS3BucketLocationResponse();
247249
this.patchS3CreateBucketLocationConstraint();
248-
}
250+
}
249251
);
250252
}
251253

@@ -298,17 +300,17 @@ class LocalstackPlugin {
298300

299301
// overwrite bound functions for specified hook names
300302
(hookNames || []).forEach(
301-
(hookName) => {
302-
plugin.hooks[hookName] = boundOverrideFunction;
303-
const slsHooks = this.serverless.pluginManager.hooks[hookName] || [];
304-
slsHooks.forEach(
305-
(hookItem) => {
306-
if (hookItem.pluginName === pluginName) {
307-
hookItem.hook = boundOverrideFunction;
308-
}
309-
}
310-
);
311-
}
303+
(hookName) => {
304+
plugin.hooks[hookName] = boundOverrideFunction;
305+
const slsHooks = this.serverless.pluginManager.hooks[hookName] || [];
306+
slsHooks.forEach(
307+
(hookItem) => {
308+
if (hookItem.pluginName === pluginName) {
309+
hookItem.hook = boundOverrideFunction;
310+
}
311+
}
312+
);
313+
}
312314
);
313315
}
314316

@@ -412,18 +414,18 @@ class LocalstackPlugin {
412414

413415
const getContainer = () => {
414416
return exec('docker ps').then(
415-
(stdout) => {
416-
const exists = stdout.split('\n').filter(
417-
(line) => (
418-
line.indexOf('localstack/localstack') >= 0 ||
419-
line.indexOf('localstack/localstack-pro') >= 0 ||
420-
line.indexOf('localstack_localstack') >= 0
421-
)
422-
);
423-
if (exists.length) {
424-
return exists[0].replace('\t', ' ').split(' ')[0];
417+
(stdout) => {
418+
const exists = stdout.split('\n').filter(
419+
(line) => (
420+
line.indexOf('localstack/localstack') >= 0 ||
421+
line.indexOf('localstack/localstack-pro') >= 0 ||
422+
line.indexOf('localstack_localstack') >= 0
423+
)
424+
);
425+
if (exists.length) {
426+
return exists[0].replace('\t', ' ').split(' ')[0];
427+
}
425428
}
426-
}
427429
)
428430
};
429431

@@ -438,13 +440,13 @@ class LocalstackPlugin {
438440
return this.sleep(4000).then(() => {
439441
this.log(`Checking state of LocalStack container ${containerID}`)
440442
return exec(`docker logs "${containerID}"`).then(
441-
(logs) => {
442-
const ready = logs.split('\n').filter((line) => line.indexOf('Ready.') >= 0);
443-
if (ready.length) {
444-
return Promise.resolve();
443+
(logs) => {
444+
const ready = logs.split('\n').filter((line) => line.indexOf('Ready.') >= 0);
445+
if (ready.length) {
446+
return Promise.resolve();
447+
}
448+
return checkStatus(containerID, timeout);
445449
}
446-
return checkStatus(containerID, timeout);
447-
}
448450
);
449451
});
450452
}
@@ -483,17 +485,17 @@ class LocalstackPlugin {
483485
}
484486

485487
return getContainer().then(
486-
(containerID) => {
487-
if(containerID) {
488-
return;
489-
}
488+
(containerID) => {
489+
if(containerID) {
490+
return;
491+
}
490492

491-
if(this.config.docker && this.config.docker.compose_file){
493+
if(this.config.docker && this.config.docker.compose_file){
492494
return startCompose();
493-
}
495+
}
494496

495-
return startContainer();
496-
}
497+
return startContainer();
498+
}
497499
);
498500
}
499501

@@ -508,12 +510,12 @@ class LocalstackPlugin {
508510
const template = this.serverless.service.provider.compiledCloudFormationTemplate || {};
509511
const resources = template.Resources || {};
510512
Object.keys(resources).forEach(
511-
(resName) => {
512-
const resEntry = resources[resName];
513-
if (resEntry.Type === 'AWS::Lambda::Function') {
514-
resEntry.Properties.Handler = `${this.getTSBuildDir()}/${resEntry.Properties.Handler}`;
513+
(resName) => {
514+
const resEntry = resources[resName];
515+
if (resEntry.Type === 'AWS::Lambda::Function') {
516+
resEntry.Properties.Handler = `${this.getTSBuildDir()}/${resEntry.Properties.Handler}`;
517+
}
515518
}
516-
}
517519
);
518520
}
519521

@@ -540,9 +542,9 @@ class LocalstackPlugin {
540542
}
541543

542544
/**
543-
* Patch S3 createBucket invocation to not add a LocationContraint if the region is `us-east-1`
544-
* The default SDK check was against endpoint and not the region directly.
545-
*/
545+
* Patch S3 createBucket invocation to not add a LocationContraint if the region is `us-east-1`
546+
* The default SDK check was against endpoint and not the region directly.
547+
*/
546548
patchS3CreateBucketLocationConstraint () {
547549
AWS.util.update(AWS.S3.prototype, {
548550
createBucket: function createBucket (params, callback) {
@@ -646,7 +648,7 @@ class LocalstackPlugin {
646648
else {
647649
this.endpoints = {}
648650
this.log("Skipping serverless-localstack:\ncustom.localstack.stages: " +
649-
JSON.stringify(this.config.stages) + "\nstage: " + this.config.stage
651+
JSON.stringify(this.config.stages) + "\nstage: " + this.config.stage
650652
)
651653
}
652654
}
@@ -700,8 +702,23 @@ class LocalstackPlugin {
700702

701703
/* Utility functions below */
702704

705+
getEndpointPort(){
706+
const url = new URL(awsEndpointUrl);
707+
return url.port;
708+
}
709+
710+
getEndpointHostname(){
711+
const url = new URL(awsEndpointUrl);
712+
return url.hostname;
713+
}
714+
715+
getEndpointProtocol(){
716+
const url = new URL(awsEndpointUrl);
717+
return url.protocol.replace(":","");
718+
}
719+
703720
getEdgePort() {
704-
return process.env.EDGE_PORT || this.config.edgePort || DEFAULT_EDGE_PORT;
721+
return process.env.EDGE_PORT || this.config.edgePort || this.getEndpointPort();
705722
}
706723

707724
/**
@@ -713,7 +730,7 @@ class LocalstackPlugin {
713730
return resolvedHostname;
714731
}
715732

716-
var hostname = process.env.LOCALSTACK_HOSTNAME || 'localhost';
733+
var hostname = process.env.LOCALSTACK_HOSTNAME || this.getEndpointHostname();
717734
if (this.config.host) {
718735
hostname = this.config.host;
719736
if (hostname.indexOf("://") !== -1) {
@@ -782,13 +799,19 @@ class LocalstackPlugin {
782799
return this.injectHostnameIntoLocalhostURL(process.env.AWS_ENDPOINT_URL, hostname);
783800
}
784801
hostname = hostname || 'localhost';
785-
const proto = TRUE_VALUES.includes(process.env.USE_SSL) ? 'https' : 'http';
802+
803+
let proto = this.getEndpointProtocol();
804+
if (process.env.USE_SSL) {
805+
proto = TRUE_VALUES.includes(process.env.USE_SSL) ? 'https' : 'http';
806+
}else if (this.config.host){
807+
proto = this.config.host.split("://")[0];
808+
}
786809
const port = this.getEdgePort();
787810
// little hack here - required to remove the default HTTPS port 443, as otherwise
788811
// routing for some platforms and ephemeral instances (e.g., on namespace.so) fails
789812
const isDefaultPort =
790-
(proto === 'http' && `${port}` === '80') ||
791-
(proto === 'https' && `${port}` === '443');
813+
(proto === 'http' && `${port}` === '80') ||
814+
(proto === 'https' && `${port}` === '443');
792815
if (isDefaultPort) {
793816
return `${proto}://${hostname}`;
794817
}
@@ -850,14 +873,14 @@ class LocalstackPlugin {
850873
patchCustomResourceLambdaS3ForcePathStyle () {
851874
const awsProvider = this.awsProvider;
852875
const patchMarker = path.join(
853-
awsProvider.serverless.serviceDir,
854-
'.serverless',
855-
'.internal-custom-resources-patched'
876+
awsProvider.serverless.serviceDir,
877+
'.serverless',
878+
'.internal-custom-resources-patched'
856879
);
857880
const zipFilePath = path.join(
858-
awsProvider.serverless.serviceDir,
859-
'.serverless',
860-
awsProvider.naming.getCustomResourcesArtifactName()
881+
awsProvider.serverless.serviceDir,
882+
'.serverless',
883+
awsProvider.naming.getCustomResourcesArtifactName()
861884
);
862885

863886
function fileExists (filePath) {

0 commit comments

Comments
 (0)