From 2a3384debd0e086ee2ca7dc2d837e6dc32763ce1 Mon Sep 17 00:00:00 2001 From: Waldemar Hummer Date: Thu, 21 Sep 2023 13:25:27 +0200 Subject: [PATCH] unify construction of target endpoint URL, add support for configuring `AWS_ENDPOINT_URL` (#234) --- README.md | 7 +++++-- package-lock.json | 4 ++-- package.json | 10 +++++----- src/index.js | 38 +++++++++++++++++++++++++++++++------- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 123cd78..d5e2e06 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,10 @@ custom: ### Configuration via environment variables The following environment variables can be configured (taking precedence over the values in `serverless.yml`): -* `EDGE_PORT`: LocalStack edge port to connect to (default: `4566`) -* `LOCALSTACK_HOSTNAME`: LocalStack host name to connect to (default: `localhost`) +* `AWS_ENDPOINT_URL`: LocalStack endpoint URL to connect to (default: `http://localhost:4566`). This is the recommended configuration, and replaces the deprecated config options (`EDGE_PORT`/`LOCALSTACK_HOSTNAME`/`USE_SSL`) below. +* `EDGE_PORT`: LocalStack edge port to connect to (deprecated; default: `4566`) +* `LOCALSTACK_HOSTNAME`: LocalStack host name to connect to (deprecated; default: `localhost`) +* `USE_SSL`: Whether to use SSL/HTTPS when connecting to the LocalStack endpoint (deprecated) ### Activating the plugin for certain stages @@ -206,6 +208,7 @@ custom: ## Change Log +* v1.1.2: Unify construction of target endpoint URL, add support for configuring `AWS_ENDPOINT_URL` * v1.1.1: Fix layer deployment if `mountCode` is enabled by always packaging and deploying * v1.1.0: Fix SSM environment variables resolving issues with serverless v3, change default for `BUCKET_MARKER_LOCAL` to `hot-reload` * v1.0.6: Add `BUCKET_MARKER_LOCAL` configuration for customizing S3 bucket for lambda mount and [Hot Reloading](https://docs.localstack.cloud/user-guide/tools/lambda-tools/hot-reloading/). diff --git a/package-lock.json b/package-lock.json index 1d617f8..e7375ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "serverless-localstack", - "version": "1.1.1", + "version": "1.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "serverless-localstack", - "version": "1.1.1", + "version": "1.1.2", "license": "MIT", "dependencies": { "adm-zip": "^0.5.10", diff --git a/package.json b/package.json index 9d97393..f0f0e29 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "serverless-localstack", - "version": "1.1.1", + "version": "1.1.2", "description": "Connect Serverless to LocalStack!", "main": "src/index.js", "scripts": { @@ -19,13 +19,13 @@ "author": "LocalStack Team ", "contributors": [ "LocalStack Team ", - "temyers", "Waldemar Hummer (whummer)", + "Ben Simon Hartung (bentsku)", + "Joel Scheuner (joe4dev)", + "temyers", "Justin McCormick ", "djKooks", - "yohei1126", - "bentsku", - "Joel Scheuner (joe4dev)" + "yohei1126" ], "license": "MIT", "bugs": { diff --git a/src/index.js b/src/index.js index e80d27e..e47f20d 100644 --- a/src/index.js +++ b/src/index.js @@ -553,7 +553,7 @@ class LocalstackPlugin { const slsSecretsAWS = this.findPlugin('ServerlessSecrets'); if (slsSecretsAWS) { slsSecretsAWS.config.options.providerOptions = slsSecretsAWS.config.options.providerOptions || {}; - slsSecretsAWS.config.options.providerOptions.endpoint = this.getServiceURL('ssm'); + slsSecretsAWS.config.options.providerOptions.endpoint = this.getServiceURL(); slsSecretsAWS.config.options.providerOptions.accessKeyId = 'test'; slsSecretsAWS.config.options.providerOptions.secretAccessKey = 'test'; } @@ -570,8 +570,7 @@ class LocalstackPlugin { } this.log('Using serverless-localstack'); const hostname = await this.getConnectHostname(); - const host = `http://${hostname}`; - const edgePort = this.getEdgePort(); + const configChanges = {}; // Configure dummy AWS credentials in the environment, to ensure the AWS client libs don't bail. @@ -591,7 +590,7 @@ class LocalstackPlugin { } // If a host has been configured, override each service - const localEndpoint = `${host}:${edgePort}`; + const localEndpoint = this.getServiceURL(hostname); for (const service of this.awsServices) { const serviceLower = service.toLowerCase(); @@ -758,9 +757,34 @@ class LocalstackPlugin { return this.awsProvider; } - getServiceURL() { + getServiceURL(hostname) { + if (process.env.AWS_ENDPOINT_URL) { + return this.injectHostnameIntoLocalhostURL(process.env.AWS_ENDPOINT_URL, hostname); + } + hostname = hostname || 'localhost'; const proto = TRUE_VALUES.includes(process.env.USE_SSL) ? 'https' : 'http'; - return `${proto}://localhost:${this.getEdgePort()}`; + const port = this.getEdgePort(); + // little hack here - required to remove the default HTTPS port 443, as otherwise + // routing for some platforms and ephemeral instances (e.g., on namespace.so) fails + const isDefaultPort = + (proto === 'http' && `${port}` === '80') || + (proto === 'https' && `${port}` === '443'); + if (isDefaultPort) { + return `${proto}://${hostname}`; + } + return `${proto}://${hostname}:${port}`; + } + + /** + * If the given `endpointURL` points to `localhost`, then inject the given `hostname` into the URL + * and return it. This helps fix IPv6 issues with node v18+ (see also getConnectHostname() above) + */ + injectHostnameIntoLocalhostURL(endpointURL, hostname) { + const url = new URL(endpointURL); + if (hostname && url.hostname === 'localhost') { + url.hostname = hostname; + } + return url.href; } log(msg) { @@ -786,7 +810,7 @@ class LocalstackPlugin { stepFunctionsReplaceDisplay() { const plugin = this.findPlugin('ServerlessStepFunctions'); if (plugin) { - const endpoint = this.getServiceURL() + const endpoint = this.getServiceURL(); plugin.originalDisplay = plugin.display; plugin.localstackEndpoint = endpoint;