serverless-localstack
Advanced tools
Comparing version 1.2.0 to 1.2.1
@@ -8,5 +8,18 @@ { | ||
"extends": "eslint:recommended", | ||
"rules": { | ||
"quotes": ["error", "single"], | ||
"semi": ["error", "always"], | ||
"indent": ["error", 2], | ||
"linebreak-style": ["error", "unix"], | ||
"no-console": "warn", | ||
"no-unused-vars": "warn", | ||
"no-alert": "error", | ||
"prefer-const": "error", | ||
"no-var": "error", | ||
"arrow-parens": ["error", "always"], | ||
"no-tabs": "error" | ||
}, | ||
"parserOptions": { | ||
"ecmaVersion": 2017 | ||
} | ||
} | ||
} |
{ | ||
"name": "serverless-localstack", | ||
"version": "1.2.0", | ||
"version": "1.2.1", | ||
"description": "Connect Serverless to LocalStack!", | ||
@@ -43,16 +43,17 @@ "main": "src/index.js", | ||
"chai-string": "^1.4.0", | ||
"eslint": "^8.56.0", | ||
"fs-extra": "^7.0.0", | ||
"jasmine": "^3.2.0", | ||
"js-yaml": ">=3.13.1", | ||
"json2yaml": "^1.1.0", | ||
"lodash": ">=4.17.13", | ||
"mixin-deep": ">=1.3.2", | ||
"nodemon": "^2.0.20", | ||
"prettier": "^3.2.5", | ||
"rimraf": "^2.6.2", | ||
"serverless": "^2.30.0", | ||
"set-value": ">=2.0.1", | ||
"sinon": "^6.2.0", | ||
"tempy": "^0.2.1", | ||
"eslint": "^5.5.0", | ||
"lodash": ">=4.17.13", | ||
"js-yaml": ">=3.13.1", | ||
"set-value": ">=2.0.1", | ||
"mixin-deep": ">=1.3.2" | ||
"tempy": "^0.2.1" | ||
} | ||
} |
@@ -211,2 +211,3 @@ [![Build Status](https://travis-ci.org/localstack/serverless-localstack.svg?branch=master)](https://travis-ci.org/localstack/serverless-localstack) | ||
## Change Log | ||
* v1.2.1: Fix custom-resource bucket compatibility with serverless >3.39.0, continue improving support for `AWS_ENDPOINT_URL` | ||
* v1.2.0: Add docker-compose config and fix autostart when plugin is not active | ||
@@ -213,0 +214,0 @@ * v1.1.3: Fix replacing host from environment variable `AWS_ENDPOINT_URL` |
@@ -6,5 +6,8 @@ const tempy = require('tempy'); | ||
const path = require('path'); | ||
const serverlessExec = path.join(__dirname, '../../node_modules/.bin/serverless'); | ||
const packageJson = require('../../package.json') | ||
const rimraf = require('rimraf') | ||
const serverlessExec = path.join( | ||
__dirname, | ||
'../../node_modules/.bin/serverless', | ||
); | ||
const packageJson = require('../../package.json'); | ||
const rimraf = require('rimraf'); | ||
@@ -20,8 +23,7 @@ const debug = false; | ||
environment: { | ||
LAMBDA_STAGE: '${ssm:/${opt:stage, self:provider.stage}/lambda/common/LAMBDA_STAGE}' | ||
} | ||
LAMBDA_STAGE: | ||
'${ssm:/${opt:stage, self:provider.stage}/lambda/common/LAMBDA_STAGE}', | ||
}, | ||
}, | ||
plugins: [ | ||
'serverless-localstack' | ||
], | ||
plugins: ['serverless-localstack'], | ||
custom: { | ||
@@ -31,9 +33,9 @@ localstack: { | ||
debug: debug, | ||
} | ||
}, | ||
}, | ||
functions: { | ||
hello: { | ||
handler: 'handler.hello' | ||
} | ||
} | ||
handler: 'handler.hello', | ||
}, | ||
}, | ||
}; | ||
@@ -45,10 +47,12 @@ | ||
execSync(`mkdir -p node_modules`, {cwd: dir}); | ||
execSync(`ln -s ${__dirname}/../../ node_modules/${packageJson.name}`, {cwd: dir}); | ||
execSync('mkdir -p node_modules', { cwd: dir }); | ||
execSync(`ln -s ${__dirname}/../../ node_modules/${packageJson.name}`, { | ||
cwd: dir, | ||
}); | ||
}; | ||
const execServerless = (arguments, dir) => { | ||
const execServerless = (myArguments, dir) => { | ||
process.chdir(dir); | ||
execSync(`${serverlessExec} ${arguments}`, { | ||
execSync(`${serverlessExec} ${myArguments}`, { | ||
stdio: 'inherit', | ||
@@ -60,4 +64,4 @@ stderr: 'inherit', | ||
PATH: process.env.PATH, | ||
SLS_DEBUG: debug ? '*' : '' | ||
}) | ||
SLS_DEBUG: debug ? '*' : '', | ||
}), | ||
}); | ||
@@ -83,3 +87,3 @@ }; | ||
exports.removeService = (dir) => { | ||
rimraf.sync(dir) | ||
rimraf.sync(dir); | ||
}; |
@@ -11,3 +11,3 @@ 'use strict'; | ||
region: 'us-east-1', | ||
endpoint: 'http://127.0.0.1:4566' | ||
endpoint: 'http://127.0.0.1:4566', | ||
}); | ||
@@ -25,21 +25,22 @@ AWS.config.credentials = new AWS.Credentials({ | ||
Value: 'my-value', | ||
Overwrite: true | ||
Overwrite: true, | ||
}; | ||
describe('LocalstackPlugin', () => { | ||
beforeEach( | ||
async () => { | ||
await ssm.putParameter(params).promise(); | ||
this.service = services.createService({}); | ||
beforeEach(async () => { | ||
await ssm.putParameter(params).promise(); | ||
this.service = services.createService({}); | ||
}); | ||
afterEach( () => { | ||
afterEach(() => { | ||
services.removeService(this.service); | ||
}); | ||
it('should deploy a stack', () => { | ||
services.deployService(this.service); | ||
}, LONG_TIMEOUT); | ||
}); | ||
it( | ||
'should deploy a stack', | ||
() => { | ||
services.deployService(this.service); | ||
}, | ||
LONG_TIMEOUT, | ||
); | ||
}); |
@@ -7,3 +7,3 @@ 'use strict'; | ||
const AWS = require('aws-sdk'); | ||
const Serverless = require('serverless') | ||
const Serverless = require('serverless'); | ||
let AwsProvider; | ||
@@ -21,4 +21,3 @@ try { | ||
describe("LocalstackPlugin", () => { | ||
describe('LocalstackPlugin', () => { | ||
let serverless; | ||
@@ -29,6 +28,6 @@ let awsProvider; | ||
let sandbox; | ||
let defaultPluginState = {}; | ||
let config = { | ||
const defaultPluginState = {}; | ||
const config = { | ||
host: 'http://localhost', | ||
debug: debug | ||
debug: debug, | ||
}; | ||
@@ -38,3 +37,3 @@ | ||
sandbox = sinon.createSandbox(); | ||
serverless = new Serverless({commands: ['deploy'], options: {}}); | ||
serverless = new Serverless({ commands: ['deploy'], options: {} }); | ||
awsProvider = new AwsProvider(serverless, {}); | ||
@@ -50,5 +49,5 @@ awsConfig = new AWS.Config(); | ||
if (debug) { | ||
console.log.apply(this, arguments); // eslint-disable-line no-console | ||
console.log.apply(this, arguments); // eslint-disable-line no-console | ||
} | ||
} | ||
}; | ||
} | ||
@@ -61,3 +60,3 @@ }); | ||
let simulateBeforeDeployHooks = async function(instance) { | ||
const simulateBeforeDeployHooks = async function (instance) { | ||
instance.readConfig(); | ||
@@ -89,3 +88,3 @@ instance.activatePlugin(); | ||
serverless.service.custom = { | ||
localstack: {} | ||
localstack: {}, | ||
}; | ||
@@ -97,7 +96,7 @@ instance = new LocalstackPlugin(serverless, defaultPluginState); | ||
it('should not set the endpoints if the stages config option does not include the deployment stage', async () => { | ||
serverless.service.custom.localstack.stages = ['production']; | ||
serverless.service.custom.localstack.stages = ['production']; | ||
let plugin = new LocalstackPlugin(serverless, defaultPluginState); | ||
await simulateBeforeDeployHooks(plugin); | ||
expect(plugin.endpoints).to.be.empty; | ||
const plugin = new LocalstackPlugin(serverless, defaultPluginState); | ||
await simulateBeforeDeployHooks(plugin); | ||
expect(plugin.endpoints).to.be.empty; | ||
}); | ||
@@ -108,6 +107,8 @@ | ||
let plugin = new LocalstackPlugin(serverless, {'stage':'production'}) | ||
const plugin = new LocalstackPlugin(serverless, { | ||
stage: 'production', | ||
}); | ||
await simulateBeforeDeployHooks(plugin); | ||
expect(plugin.config.stages).to.deep.equal(['production','staging']); | ||
expect(plugin.config.stages).to.deep.equal(['production', 'staging']); | ||
expect(plugin.config.stage).to.equal('production'); | ||
@@ -119,11 +120,13 @@ }); | ||
endpointFile: 'missing.json', | ||
stages: ['production'] | ||
} | ||
stages: ['production'], | ||
}; | ||
let plugin = () => { | ||
let pluginInstance = new LocalstackPlugin(serverless, {'stage':'production'}); | ||
const plugin = () => { | ||
const pluginInstance = new LocalstackPlugin(serverless, { | ||
stage: 'production', | ||
}); | ||
pluginInstance.readConfig(); | ||
} | ||
}; | ||
expect(plugin).to.throw('Endpoint file "missing.json" is invalid:') | ||
expect(plugin).to.throw('Endpoint file "missing.json" is invalid:'); | ||
}); | ||
@@ -134,11 +137,13 @@ | ||
endpointFile: 'missing.json', | ||
stages: ['production'] | ||
} | ||
stages: ['production'], | ||
}; | ||
let plugin = () => { | ||
let pluginInstance = new LocalstackPlugin(serverless, {'stage':'staging'}); | ||
const plugin = () => { | ||
const pluginInstance = new LocalstackPlugin(serverless, { | ||
stage: 'staging', | ||
}); | ||
pluginInstance.readConfig(); | ||
} | ||
}; | ||
expect(plugin).to.not.throw('Endpoint file "missing.json" is invalid:') | ||
expect(plugin).to.not.throw('Endpoint file "missing.json" is invalid:'); | ||
}); | ||
@@ -148,11 +153,13 @@ | ||
serverless.service.custom.localstack = { | ||
endpointFile: 'README.md' | ||
} | ||
let plugin = () => { | ||
let pluginInstance = new LocalstackPlugin(serverless, defaultPluginState); | ||
endpointFile: 'README.md', | ||
}; | ||
const plugin = () => { | ||
const pluginInstance = new LocalstackPlugin( | ||
serverless, | ||
defaultPluginState, | ||
); | ||
pluginInstance.readConfig(); | ||
} | ||
expect(plugin).to.throw(/Endpoint file "README.md" is invalid:/) | ||
}; | ||
expect(plugin).to.throw(/Endpoint file "README.md" is invalid:/); | ||
}); | ||
}); | ||
@@ -162,4 +169,3 @@ }); | ||
describe('#request() bound on AWS provider', () => { | ||
beforeEach(()=> { | ||
beforeEach(() => { | ||
class FakeService { | ||
@@ -177,4 +183,4 @@ foo() { | ||
serverless.service.custom = { | ||
localstack: {} | ||
} | ||
localstack: {}, | ||
}; | ||
}); | ||
@@ -189,8 +195,12 @@ | ||
await awsProvider.request('s3', 'foo', { | ||
TemplateURL: pathToTemplate | ||
TemplateURL: pathToTemplate, | ||
}); | ||
expect(request.called).to.be.true; | ||
let templateUrl = request.firstCall.args[2].TemplateURL; | ||
const templateUrl = request.firstCall.args[2].TemplateURL; | ||
// url should either start with 'http://localhost' or 'http://127.0.0.1 | ||
expect(templateUrl).to.satisfy((url) => url === `${config.host}:4566/path/to/template` || url === 'http://127.0.0.1:4566/path/to/template'); | ||
expect(templateUrl).to.satisfy( | ||
(url) => | ||
url === `${config.host}:4566/path/to/template` || | ||
url === 'http://127.0.0.1:4566/path/to/template', | ||
); | ||
}); | ||
@@ -208,10 +218,10 @@ | ||
await awsProvider.request('s3', 'foo', { | ||
TemplateURL: pathToTemplate | ||
TemplateURL: pathToTemplate, | ||
}); | ||
// Remove the environment variable again to not affect other tests | ||
delete process.env.AWS_ENDPOINT_URL | ||
delete process.env.AWS_ENDPOINT_URL; | ||
expect(request.called).to.be.true; | ||
let templateUrl = request.firstCall.args[2].TemplateURL; | ||
const templateUrl = request.firstCall.args[2].TemplateURL; | ||
expect(templateUrl).to.equal('http://localstack:4566/path/to/template'); | ||
@@ -222,3 +232,3 @@ }); | ||
const request = sinon.stub(awsProvider, 'request'); | ||
instance = new LocalstackPlugin(serverless, defaultPluginState) | ||
instance = new LocalstackPlugin(serverless, defaultPluginState); | ||
await simulateBeforeDeployHooks(instance); | ||
@@ -230,5 +240,3 @@ | ||
}); | ||
}); | ||
}) | ||
}); |
588
src/index.js
'use strict'; | ||
const AdmZip = require("adm-zip"); | ||
const AdmZip = require('adm-zip'); | ||
const AWS = require('aws-sdk'); | ||
@@ -7,3 +7,3 @@ const fs = require('fs'); | ||
const net = require('net'); | ||
const {promisify} = require('es6-promisify'); | ||
const { promisify } = require('es6-promisify'); | ||
const exec = promisify(require('child_process').exec); | ||
@@ -16,25 +16,26 @@ | ||
// Plugin naming and build directory of serverless-plugin-typescript plugin | ||
const TS_PLUGIN_TSC = 'TypeScriptPlugin' | ||
const TS_PLUGIN_TSC = 'TypeScriptPlugin'; | ||
const TYPESCRIPT_PLUGIN_BUILD_DIR_TSC = '.build'; //TODO detect from tsconfig.json | ||
// Plugin naming and build directory of serverless-webpack plugin | ||
const TS_PLUGIN_WEBPACK = 'ServerlessWebpack' | ||
const TS_PLUGIN_WEBPACK = 'ServerlessWebpack'; | ||
const TYPESCRIPT_PLUGIN_BUILD_DIR_WEBPACK = '.webpack/service'; //TODO detect from webpack.config.js | ||
// Plugin naming and build directory of serverless-webpack plugin | ||
const TS_PLUGIN_ESBUILD = 'EsbuildServerlessPlugin' | ||
const TS_PLUGIN_ESBUILD = 'EsbuildServerlessPlugin'; | ||
const TYPESCRIPT_PLUGIN_BUILD_DIR_ESBUILD = '.esbuild/.build'; //TODO detect from esbuild.config.js | ||
// Default edge port to use with host | ||
const DEFAULT_EDGE_PORT = '4566'; | ||
// Default AWS endpoint URL | ||
const DEFAULT_AWS_ENDPOINT_URL = 'http://localhost:4566'; | ||
// Cache hostname to avoid unnecessary connection checks | ||
var resolvedHostname = undefined; | ||
let resolvedHostname = undefined; | ||
const awsEndpointUrl = process.env.AWS_ENDPOINT_URL || DEFAULT_AWS_ENDPOINT_URL; | ||
class LocalstackPlugin { | ||
constructor(serverless, options) { | ||
this.serverless = serverless; | ||
this.options = options; | ||
this.hooks = {'initialize': () => this.init()}; | ||
this.hooks = { initialize: () => this.init() }; | ||
// Define a before-hook for all event types | ||
for (let event in this.serverless.pluginManager.hooks) { | ||
for (const event in this.serverless.pluginManager.hooks) { | ||
const doAdd = event.startsWith('before:'); | ||
@@ -49,13 +50,24 @@ if (doAdd && !this.hooks[event]) { | ||
// Define a hook for deploy:deploy to fix handler location for mounted lambda | ||
this.addHookInFirstPosition('deploy:deploy', this.patchTypeScriptPluginMountedCodeLocation); | ||
this.addHookInFirstPosition( | ||
'deploy:deploy', | ||
this.patchTypeScriptPluginMountedCodeLocation, | ||
); | ||
// Add a before hook for aws:common:validate and make sure it is in the very first position | ||
this.addHookInFirstPosition('before:aws:common:validate:validate', this.beforeEventHook); | ||
this.addHookInFirstPosition( | ||
'before:aws:common:validate:validate', | ||
this.beforeEventHook, | ||
); | ||
// Add a hook to fix TypeError when accessing undefined state attribute | ||
this.addHookInFirstPosition('before:aws:deploy:deploy:checkForChanges', this.beforeDeployCheckForChanges); | ||
this.addHookInFirstPosition( | ||
'before:aws:deploy:deploy:checkForChanges', | ||
this.beforeDeployCheckForChanges, | ||
); | ||
const compileEventsHooks = this.serverless.pluginManager.hooks['package:compileEvents'] || []; | ||
const compileEventsHooks = | ||
this.serverless.pluginManager.hooks['package:compileEvents'] || []; | ||
compileEventsHooks.push({ | ||
pluginName: 'LocalstackPlugin', hook: this.patchCustomResourceLambdaS3ForcePathStyle.bind(this) | ||
pluginName: 'LocalstackPlugin', | ||
hook: this.patchCustomResourceLambdaS3ForcePathStyle.bind(this), | ||
}); | ||
@@ -140,6 +152,8 @@ | ||
if (this.detectTypescriptPluginType() === TS_PLUGIN_WEBPACK) { | ||
const p = this.serverless.pluginManager.plugins.find((x) => x.constructor.name === TS_PLUGIN_WEBPACK); | ||
const p = this.serverless.pluginManager.plugins.find( | ||
(x) => x.constructor.name === TS_PLUGIN_WEBPACK, | ||
); | ||
if ( | ||
this.shouldMountCode() && ( | ||
!p || | ||
this.shouldMountCode() && | ||
(!p || | ||
!p.serverless || | ||
@@ -149,7 +163,8 @@ !p.serverless.configurationInput || | ||
!p.serverless.configurationInput.custom.webpack || | ||
!p.serverless.configurationInput.custom.webpack.keepOutputDirectory | ||
) | ||
!p.serverless.configurationInput.custom.webpack.keepOutputDirectory) | ||
) { | ||
throw new Error('When mounting Lambda code, you must retain webpack output directory. ' | ||
+ 'Set custom.webpack.keepOutputDirectory to true.'); | ||
throw new Error( | ||
'When mounting Lambda code, you must retain webpack output directory. ' + | ||
'Set custom.webpack.keepOutputDirectory to true.', | ||
); | ||
} | ||
@@ -160,9 +175,12 @@ } | ||
async init() { | ||
await this.reconfigureAWS() | ||
await this.reconfigureAWS(); | ||
} | ||
addHookInFirstPosition(eventName, hookFunction) { | ||
this.serverless.pluginManager.hooks[eventName] = this.serverless.pluginManager.hooks[eventName] || []; | ||
this.serverless.pluginManager.hooks[eventName].unshift( | ||
{ pluginName: 'LocalstackPlugin', hook: hookFunction.bind(this, eventName) }); | ||
this.serverless.pluginManager.hooks[eventName] = | ||
this.serverless.pluginManager.hooks[eventName] || []; | ||
this.serverless.pluginManager.hooks[eventName].unshift({ | ||
pluginName: 'LocalstackPlugin', | ||
hook: hookFunction.bind(this, eventName), | ||
}); | ||
} | ||
@@ -192,31 +210,53 @@ | ||
functionObject.package.artifact = __filename; | ||
return compileFunction._functionOriginal.apply(null, arguments).then(() => { | ||
const resources = this.serverless.service.provider.compiledCloudFormationTemplate.Resources; | ||
Object.keys(resources).forEach(id => { | ||
const res = resources[id]; | ||
if (res.Type === 'AWS::Lambda::Function') { | ||
res.Properties.Code.S3Bucket = process.env.BUCKET_MARKER_LOCAL || 'hot-reload'; // default changed to 'hot-reload' with LS v2 release | ||
res.Properties.Code.S3Key = process.cwd(); | ||
const mountCode = this.config.lambda.mountCode; | ||
if (typeof mountCode === 'string' && mountCode.toLowerCase() !== 'true') { | ||
res.Properties.Code.S3Key = path.join(res.Properties.Code.S3Key, this.config.lambda.mountCode); | ||
return compileFunction._functionOriginal | ||
.apply(null, arguments) | ||
.then(() => { | ||
const resources = | ||
this.serverless.service.provider.compiledCloudFormationTemplate | ||
.Resources; | ||
Object.keys(resources).forEach((id) => { | ||
const res = resources[id]; | ||
if (res.Type === 'AWS::Lambda::Function') { | ||
res.Properties.Code.S3Bucket = | ||
process.env.BUCKET_MARKER_LOCAL || 'hot-reload'; // default changed to 'hot-reload' with LS v2 release | ||
res.Properties.Code.S3Key = process.cwd(); | ||
const mountCode = this.config.lambda.mountCode; | ||
if ( | ||
typeof mountCode === 'string' && | ||
mountCode.toLowerCase() !== 'true' | ||
) { | ||
res.Properties.Code.S3Key = path.join( | ||
res.Properties.Code.S3Key, | ||
this.config.lambda.mountCode, | ||
); | ||
} | ||
if (process.env.LAMBDA_MOUNT_CWD) { | ||
// Allow users to define a custom working directory for Lambda mounts. | ||
// For example, when deploying a Serverless app in a Linux VM (that runs Docker) on a | ||
// Windows host where the "-v <local_dir>:<cont_dir>" flag to "docker run" requires us | ||
// to specify a "local_dir" relative to the Windows host file system that is mounted | ||
// into the VM (e.g., "c:/users/guest/..."). | ||
res.Properties.Code.S3Key = process.env.LAMBDA_MOUNT_CWD; | ||
} | ||
} | ||
if (process.env.LAMBDA_MOUNT_CWD) { | ||
// Allow users to define a custom working directory for Lambda mounts. | ||
// For example, when deploying a Serverless app in a Linux VM (that runs Docker) on a | ||
// Windows host where the "-v <local_dir>:<cont_dir>" flag to "docker run" requires us | ||
// to specify a "local_dir" relative to the Windows host file system that is mounted | ||
// into the VM (e.g., "c:/users/guest/..."). | ||
res.Properties.Code.S3Key = process.env.LAMBDA_MOUNT_CWD; | ||
} | ||
} | ||
}); | ||
}); | ||
}); | ||
} | ||
this.skipIfMountLambda('AwsCompileFunctions', 'compileFunction', compileFunction); | ||
this.skipIfMountLambda( | ||
'AwsCompileFunctions', | ||
'compileFunction', | ||
compileFunction, | ||
); | ||
this.skipIfMountLambda('AwsCompileFunctions', 'downloadPackageArtifacts'); | ||
this.skipIfMountLambda('AwsDeploy', 'extendedValidate'); | ||
if (this.detectTypescriptPluginType()) { | ||
this.skipIfMountLambda(this.detectTypescriptPluginType(), 'cleanup', null, [ | ||
'after:package:createDeploymentArtifacts', 'after:deploy:function:packageFunction']); | ||
this.skipIfMountLambda( | ||
this.detectTypescriptPluginType(), | ||
'cleanup', | ||
null, | ||
[ | ||
'after:package:createDeploymentArtifacts', | ||
'after:deploy:function:packageFunction', | ||
], | ||
); | ||
} | ||
@@ -250,9 +290,7 @@ | ||
return this.startLocalStack().then( | ||
() => { | ||
this.patchServerlessSecrets(); | ||
this.patchS3BucketLocationResponse(); | ||
this.patchS3CreateBucketLocationConstraint(); | ||
} | ||
); | ||
return this.startLocalStack().then(() => { | ||
this.patchServerlessSecrets(); | ||
this.patchS3BucketLocationResponse(); | ||
this.patchS3CreateBucketLocationConstraint(); | ||
}); | ||
} | ||
@@ -262,6 +300,6 @@ | ||
detectTypescriptPluginType() { | ||
if (this.findPlugin(TS_PLUGIN_TSC)) return TS_PLUGIN_TSC | ||
if (this.findPlugin(TS_PLUGIN_WEBPACK)) return TS_PLUGIN_WEBPACK | ||
if (this.findPlugin(TS_PLUGIN_ESBUILD)) return TS_PLUGIN_ESBUILD | ||
return undefined | ||
if (this.findPlugin(TS_PLUGIN_TSC)) return TS_PLUGIN_TSC; | ||
if (this.findPlugin(TS_PLUGIN_WEBPACK)) return TS_PLUGIN_WEBPACK; | ||
if (this.findPlugin(TS_PLUGIN_ESBUILD)) return TS_PLUGIN_ESBUILD; | ||
return undefined; | ||
} | ||
@@ -271,11 +309,15 @@ | ||
getTSBuildDir() { | ||
const TS_PLUGIN = this.detectTypescriptPluginType() | ||
if (TS_PLUGIN === TS_PLUGIN_TSC) return TYPESCRIPT_PLUGIN_BUILD_DIR_TSC | ||
if (TS_PLUGIN === TS_PLUGIN_WEBPACK) return TYPESCRIPT_PLUGIN_BUILD_DIR_WEBPACK | ||
if (TS_PLUGIN === TS_PLUGIN_ESBUILD) return TYPESCRIPT_PLUGIN_BUILD_DIR_ESBUILD | ||
return undefined | ||
const TS_PLUGIN = this.detectTypescriptPluginType(); | ||
if (TS_PLUGIN === TS_PLUGIN_TSC) return TYPESCRIPT_PLUGIN_BUILD_DIR_TSC; | ||
if (TS_PLUGIN === TS_PLUGIN_WEBPACK) | ||
return TYPESCRIPT_PLUGIN_BUILD_DIR_WEBPACK; | ||
if (TS_PLUGIN === TS_PLUGIN_ESBUILD) | ||
return TYPESCRIPT_PLUGIN_BUILD_DIR_ESBUILD; | ||
return undefined; | ||
} | ||
findPlugin(name) { | ||
return this.serverless.pluginManager.plugins.find(p => p.constructor.name === name); | ||
return this.serverless.pluginManager.plugins.find( | ||
(p) => p.constructor.name === name, | ||
); | ||
} | ||
@@ -286,7 +328,9 @@ | ||
if (!plugin) { | ||
this.log('Warning: Unable to find plugin named: ' + pluginName) | ||
this.log('Warning: Unable to find plugin named: ' + pluginName); | ||
return; | ||
} | ||
if (!plugin[functionName]) { | ||
this.log(`Unable to find function ${functionName} on plugin ${pluginName}`) | ||
this.log( | ||
`Unable to find function ${functionName} on plugin ${pluginName}`, | ||
); | ||
return; | ||
@@ -299,3 +343,5 @@ } | ||
const fqn = pluginName + '.' + functionName; | ||
this.log('Skip plugin function ' + fqn + ' (lambda.mountCode flag is enabled)'); | ||
this.log( | ||
'Skip plugin function ' + fqn + ' (lambda.mountCode flag is enabled)', | ||
); | ||
return Promise.resolve(); | ||
@@ -312,15 +358,11 @@ } | ||
// overwrite bound functions for specified hook names | ||
(hookNames || []).forEach( | ||
(hookName) => { | ||
plugin.hooks[hookName] = boundOverrideFunction; | ||
const slsHooks = this.serverless.pluginManager.hooks[hookName] || []; | ||
slsHooks.forEach( | ||
(hookItem) => { | ||
if (hookItem.pluginName === pluginName) { | ||
hookItem.hook = boundOverrideFunction; | ||
} | ||
} | ||
); | ||
} | ||
); | ||
(hookNames || []).forEach((hookName) => { | ||
plugin.hooks[hookName] = boundOverrideFunction; | ||
const slsHooks = this.serverless.pluginManager.hooks[hookName] || []; | ||
slsHooks.forEach((hookItem) => { | ||
if (hookItem.pluginName === pluginName) { | ||
hookItem.hook = boundOverrideFunction; | ||
} | ||
}); | ||
}); | ||
} | ||
@@ -333,7 +375,8 @@ | ||
const localstackConfig = (this.serverless.service.custom || {}).localstack || {}; | ||
const localstackConfig = | ||
(this.serverless.service.custom || {}).localstack || {}; | ||
this.config = Object.assign({}, this.options, localstackConfig); | ||
//Get the target deployment stage | ||
this.config.stage = ""; | ||
this.config.stage = ''; | ||
this.config.options_stage = this.options.stage || undefined; | ||
@@ -370,5 +413,8 @@ | ||
// (2) serverless is invoked without a --stage flag (default stage "dev") and no `stages` config is provided | ||
const effectiveStage = this.options.stage || this.config.stage || DEFAULT_STAGE; | ||
const noStageUsed = this.config.stages === undefined && effectiveStage == DEFAULT_STAGE; | ||
const includedInStages = this.config.stages && this.config.stages.includes(effectiveStage); | ||
const effectiveStage = | ||
this.options.stage || this.config.stage || DEFAULT_STAGE; | ||
const noStageUsed = | ||
this.config.stages === undefined && effectiveStage == DEFAULT_STAGE; | ||
const includedInStages = | ||
this.config.stages && this.config.stages.includes(effectiveStage); | ||
return noStageUsed || includedInStages; | ||
@@ -391,3 +437,4 @@ } | ||
this.debug('serverless.service.provider.stage: ' + providerConfig.stage); | ||
this.config.stage = this.config.options_stage || customConfig.stage || providerConfig.stage; | ||
this.config.stage = | ||
this.config.options_stage || customConfig.stage || providerConfig.stage; | ||
this.debug('config.stage: ' + this.config.stage); | ||
@@ -397,3 +444,3 @@ } | ||
fixOutputEndpoints() { | ||
if(!this.isActive()) { | ||
if (!this.isActive()) { | ||
return; | ||
@@ -413,3 +460,4 @@ } | ||
// - https://2e22431f.execute-api.us-east-1.amazonaws.com | ||
const regex2 = /[^\s:]*:\/\/([^.]+)\.execute-api\.[^/]+(([^/]+)(\/.*)?)?\/*$/g; | ||
const regex2 = | ||
/[^\s:]*:\/\/([^.]+)\.execute-api\.[^/]+(([^/]+)(\/.*)?)?\/*$/g; | ||
const replace2 = `https://$1.execute-api.localhost.localstack.cloud:${edgePort}$2`; | ||
@@ -420,3 +468,3 @@ endpoints[idx] = entry.replace(regex2, replace2); | ||
// Replace ServerlessStepFunctions display | ||
this.stepFunctionsReplaceDisplay() | ||
this.stepFunctionsReplaceDisplay(); | ||
} | ||
@@ -433,16 +481,15 @@ | ||
const getContainer = () => { | ||
return exec('docker ps').then( | ||
(stdout) => { | ||
const exists = stdout.split('\n').filter( | ||
(line) => ( | ||
line.indexOf('localstack/localstack') >= 0 || | ||
line.indexOf('localstack/localstack-pro') >= 0 || | ||
line.indexOf('localstack_localstack') >= 0 | ||
) | ||
return exec('docker ps').then((stdout) => { | ||
const exists = stdout | ||
.split('\n') | ||
.filter( | ||
(line) => | ||
line.indexOf('localstack/localstack') >= 0 || | ||
line.indexOf('localstack/localstack-pro') >= 0 || | ||
line.indexOf('localstack_localstack') >= 0, | ||
); | ||
if (exists.length) { | ||
return exists[0].replace('\t', ' ').split(' ')[0]; | ||
} | ||
if (exists.length) { | ||
return exists[0].replace('\t', ' ').split(' ')[0]; | ||
} | ||
) | ||
}); | ||
}; | ||
@@ -455,27 +502,31 @@ | ||
if (Date.now() > timeout) { | ||
this.log('Warning: Timeout when checking state of LocalStack container'); | ||
this.log( | ||
'Warning: Timeout when checking state of LocalStack container', | ||
); | ||
return; | ||
} | ||
return this.sleep(4000).then(() => { | ||
this.log(`Checking state of LocalStack container ${containerID}`) | ||
return exec(`docker logs "${containerID}"`).then( | ||
(logs) => { | ||
const ready = logs.split('\n').filter((line) => line.indexOf('Ready.') >= 0); | ||
if (ready.length) { | ||
return Promise.resolve(); | ||
} | ||
return checkStatus(containerID, timeout); | ||
this.log(`Checking state of LocalStack container ${containerID}`); | ||
return exec(`docker logs "${containerID}"`).then((logs) => { | ||
const ready = logs | ||
.split('\n') | ||
.filter((line) => line.indexOf('Ready.') >= 0); | ||
if (ready.length) { | ||
return Promise.resolve(); | ||
} | ||
); | ||
return checkStatus(containerID, timeout); | ||
}); | ||
}); | ||
} | ||
}; | ||
const addNetworks = async (containerID) => { | ||
if(this.config.networks) { | ||
for(var network in this.config.networks) { | ||
await exec(`docker network connect "${this.config.networks[network]}" ${containerID}`); | ||
if (this.config.networks) { | ||
for (const network in this.config.networks) { | ||
await exec( | ||
`docker network connect "${this.config.networks[network]}" ${containerID}`, | ||
); | ||
} | ||
} | ||
return containerID; | ||
} | ||
}; | ||
@@ -491,30 +542,33 @@ const startContainer = () => { | ||
env.START_WEB = env.START_WEB || '0'; | ||
const maxBuffer = (+env.EXEC_MAXBUFFER)||50*1000*1000; // 50mb buffer to handle output | ||
const maxBuffer = +env.EXEC_MAXBUFFER || 50 * 1000 * 1000; // 50mb buffer to handle output | ||
if (this.shouldRunDockerSudo()) { | ||
env.DOCKER_CMD = 'sudo docker'; | ||
} | ||
const options = {env: env, maxBuffer}; | ||
return exec('localstack start -d', options).then(getContainer) | ||
.then((containerID) => addNetworks(containerID)) | ||
.then((containerID) => checkStatus(containerID)); | ||
} | ||
const options = { env: env, maxBuffer }; | ||
return exec('localstack start -d', options) | ||
.then(getContainer) | ||
.then((containerID) => addNetworks(containerID)) | ||
.then((containerID) => checkStatus(containerID)); | ||
}; | ||
const startCompose = () => { | ||
this.log('Starting LocalStack using the provided docker-compose file. This can take a while.'); | ||
return exec(`docker-compose -f ${this.config.docker.compose_file} up -d`).then(getContainer) | ||
} | ||
this.log( | ||
'Starting LocalStack using the provided docker-compose file. This can take a while.', | ||
); | ||
return exec( | ||
`docker-compose -f ${this.config.docker.compose_file} up -d`, | ||
).then(getContainer); | ||
}; | ||
return getContainer().then( | ||
(containerID) => { | ||
if(containerID) { | ||
return; | ||
} | ||
return getContainer().then((containerID) => { | ||
if (containerID) { | ||
return; | ||
} | ||
if(this.config.docker && this.config.docker.compose_file){ | ||
return startCompose(); | ||
} | ||
if (this.config.docker && this.config.docker.compose_file) { | ||
return startCompose(); | ||
} | ||
return startContainer(); | ||
} | ||
); | ||
return startContainer(); | ||
}); | ||
} | ||
@@ -527,15 +581,18 @@ | ||
patchTypeScriptPluginMountedCodeLocation() { | ||
if (!this.shouldMountCode() || !this.detectTypescriptPluginType() || !this.isActive()) { | ||
if ( | ||
!this.shouldMountCode() || | ||
!this.detectTypescriptPluginType() || | ||
!this.isActive() | ||
) { | ||
return; | ||
} | ||
const template = this.serverless.service.provider.compiledCloudFormationTemplate || {}; | ||
const template = | ||
this.serverless.service.provider.compiledCloudFormationTemplate || {}; | ||
const resources = template.Resources || {}; | ||
Object.keys(resources).forEach( | ||
(resName) => { | ||
const resEntry = resources[resName]; | ||
if (resEntry.Type === 'AWS::Lambda::Function') { | ||
resEntry.Properties.Handler = `${this.getTSBuildDir()}/${resEntry.Properties.Handler}`; | ||
} | ||
Object.keys(resources).forEach((resName) => { | ||
const resEntry = resources[resName]; | ||
if (resEntry.Type === 'AWS::Lambda::Function') { | ||
resEntry.Properties.Handler = `${this.getTSBuildDir()}/${resEntry.Properties.Handler}`; | ||
} | ||
); | ||
}); | ||
} | ||
@@ -556,3 +613,3 @@ | ||
return Promise.resolve(res); | ||
}) | ||
}); | ||
} | ||
@@ -567,8 +624,8 @@ return result; | ||
/** | ||
* Patch S3 createBucket invocation to not add a LocationContraint if the region is `us-east-1` | ||
* The default SDK check was against endpoint and not the region directly. | ||
*/ | ||
patchS3CreateBucketLocationConstraint () { | ||
* Patch S3 createBucket invocation to not add a LocationContraint if the region is `us-east-1` | ||
* The default SDK check was against endpoint and not the region directly. | ||
*/ | ||
patchS3CreateBucketLocationConstraint() { | ||
AWS.util.update(AWS.S3.prototype, { | ||
createBucket: function createBucket (params, callback) { | ||
createBucket: function createBucket(params, callback) { | ||
// When creating a bucket *outside* the classic region, the location | ||
@@ -585,9 +642,14 @@ // constraint must be set for the bucket and it must match the endpoint. | ||
// mutate params object argument passed in by user | ||
var copiedParams = AWS.util.copy(params); | ||
if (this.config.region !== 'us-east-1' && !params.CreateBucketConfiguration) { | ||
copiedParams.CreateBucketConfiguration = { LocationConstraint: this.config.region }; | ||
const copiedParams = AWS.util.copy(params); | ||
if ( | ||
this.config.region !== 'us-east-1' && | ||
!params.CreateBucketConfiguration | ||
) { | ||
copiedParams.CreateBucketConfiguration = { | ||
LocationConstraint: this.config.region, | ||
}; | ||
} | ||
return this.makeRequest('createBucket', copiedParams, callback); | ||
} | ||
}) | ||
}, | ||
}); | ||
} | ||
@@ -601,4 +663,6 @@ | ||
if (slsSecretsAWS) { | ||
slsSecretsAWS.config.options.providerOptions = slsSecretsAWS.config.options.providerOptions || {}; | ||
slsSecretsAWS.config.options.providerOptions.endpoint = this.getServiceURL(); | ||
slsSecretsAWS.config.options.providerOptions = | ||
slsSecretsAWS.config.options.providerOptions || {}; | ||
slsSecretsAWS.config.options.providerOptions.endpoint = | ||
this.getServiceURL(); | ||
slsSecretsAWS.config.options.providerOptions.accessKeyId = 'test'; | ||
@@ -613,5 +677,7 @@ slsSecretsAWS.config.options.providerOptions.secretAccessKey = 'test'; | ||
async reconfigureAWS() { | ||
if(this.isActive()) { | ||
if(this.reconfiguredEndpoints){ | ||
this.debug("Skipping reconfiguring of endpoints (already reconfigured)") | ||
if (this.isActive()) { | ||
if (this.reconfiguredEndpoints) { | ||
this.debug( | ||
'Skipping reconfiguring of endpoints (already reconfigured)', | ||
); | ||
return; | ||
@@ -627,6 +693,9 @@ } | ||
const tmpCreds = awsProvider.getCredentials(); | ||
if (!tmpCreds.credentials){ | ||
if (!tmpCreds.credentials) { | ||
const accessKeyId = process.env.AWS_ACCESS_KEY_ID || 'test'; | ||
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY || 'test'; | ||
const fakeCredentials = new AWS.Credentials({accessKeyId, secretAccessKey}); | ||
const fakeCredentials = new AWS.Credentials({ | ||
accessKeyId, | ||
secretAccessKey, | ||
}); | ||
configChanges.credentials = fakeCredentials; | ||
@@ -672,11 +741,13 @@ // set environment variables, ... | ||
} | ||
this.log("serverless-localstack: Reconfigured endpoints") | ||
this.log('serverless-localstack: Reconfigured endpoints'); | ||
this.reconfiguredEndpoints = true; | ||
} else { | ||
this.endpoints = {}; | ||
this.log( | ||
'Skipping serverless-localstack:\ncustom.localstack.stages: ' + | ||
JSON.stringify(this.config.stages) + | ||
'\nstage: ' + | ||
this.config.stage, | ||
); | ||
} | ||
else { | ||
this.endpoints = {} | ||
this.log("Skipping serverless-localstack:\ncustom.localstack.stages: " + | ||
JSON.stringify(this.config.stages) + "\nstage: " + this.config.stage | ||
) | ||
} | ||
} | ||
@@ -693,5 +764,7 @@ | ||
try { | ||
endpointJson = JSON.parse( fs.readFileSync(endpointFile) ); | ||
} catch(err) { | ||
throw new ReferenceError(`Endpoint file "${this.endpointFile}" is invalid: ${err}`) | ||
endpointJson = JSON.parse(fs.readFileSync(endpointFile)); | ||
} catch (err) { | ||
throw new ReferenceError( | ||
`Endpoint file "${this.endpointFile}" is invalid: ${err}`, | ||
); | ||
} | ||
@@ -706,3 +779,2 @@ | ||
async interceptRequest(service, method, params) { | ||
// Enable the plugin here, if not yet enabled (the function call below is idempotent). | ||
@@ -714,3 +786,3 @@ // TODO: It seems that we can potentially remove the hooks / plugin loading logic | ||
// Template validation is not supported in LocalStack | ||
if (method == "validateTemplate") { | ||
if (method == 'validateTemplate') { | ||
this.log('Skipping template validation: Unsupported in Localstack'); | ||
@@ -720,9 +792,16 @@ return Promise.resolve(''); | ||
const config = AWS.config[service.toLowerCase()] ? AWS.config : this.getAwsProvider().sdk.config; | ||
const config = AWS.config[service.toLowerCase()] | ||
? AWS.config | ||
: this.getAwsProvider().sdk.config; | ||
if (config[service.toLowerCase()]) { | ||
this.debug(`Using custom endpoint for ${service}: ${config[service.toLowerCase()].endpoint}`); | ||
this.debug( | ||
`Using custom endpoint for ${service}: ${config[service.toLowerCase()].endpoint}`, | ||
); | ||
if (config.s3 && params.TemplateURL) { | ||
this.debug(`Overriding S3 templateUrl to ${config.s3.endpoint}`); | ||
params.TemplateURL = params.TemplateURL.replace(/https:\/\/s3.amazonaws.com/, config.s3.endpoint); | ||
params.TemplateURL = params.TemplateURL.replace( | ||
/https:\/\/s3.amazonaws.com/, | ||
config.s3.endpoint, | ||
); | ||
} | ||
@@ -737,4 +816,21 @@ } | ||
getEndpointPort() { | ||
const url = new URL(awsEndpointUrl); | ||
return url.port; | ||
} | ||
getEndpointHostname() { | ||
const url = new URL(awsEndpointUrl); | ||
return url.hostname; | ||
} | ||
getEndpointProtocol() { | ||
const url = new URL(awsEndpointUrl); | ||
return url.protocol.replace(':', ''); | ||
} | ||
getEdgePort() { | ||
return process.env.EDGE_PORT || this.config.edgePort || DEFAULT_EDGE_PORT; | ||
return ( | ||
process.env.EDGE_PORT || this.config.edgePort || this.getEndpointPort() | ||
); | ||
} | ||
@@ -751,6 +847,7 @@ | ||
var hostname = process.env.LOCALSTACK_HOSTNAME || 'localhost'; | ||
let hostname = | ||
process.env.LOCALSTACK_HOSTNAME || this.getEndpointHostname(); | ||
if (this.config.host) { | ||
hostname = this.config.host; | ||
if (hostname.indexOf("://") !== -1) { | ||
if (hostname.indexOf('://') !== -1) { | ||
hostname = new URL(hostname).hostname; | ||
@@ -765,3 +862,3 @@ } | ||
// Issue: https://github.com/localstack/serverless-localstack/issues/125 | ||
if (hostname === "localhost") { | ||
if (hostname === 'localhost') { | ||
try { | ||
@@ -772,4 +869,6 @@ const port = this.getEdgePort(); | ||
} catch (e) { | ||
const fallbackHostname = "127.0.0.1" | ||
this.debug(`Reconfiguring hostname to use ${fallbackHostname} (IPv4) because connection to ${hostname} failed`); | ||
const fallbackHostname = '127.0.0.1'; | ||
this.debug( | ||
`Reconfiguring hostname to use ${fallbackHostname} (IPv4) because connection to ${hostname} failed`, | ||
); | ||
hostname = fallbackHostname; | ||
@@ -800,4 +899,4 @@ } | ||
client.setTimeout(500); // milliseconds | ||
client.on("timeout", err => { | ||
client.setTimeout(500); // milliseconds | ||
client.on('timeout', (err) => { | ||
client.destroy(); | ||
@@ -807,3 +906,3 @@ reject(err); | ||
client.on("error", err => { | ||
client.on('error', (err) => { | ||
client.destroy(); | ||
@@ -822,6 +921,15 @@ reject(err); | ||
if (process.env.AWS_ENDPOINT_URL) { | ||
return this.injectHostnameIntoLocalhostURL(process.env.AWS_ENDPOINT_URL, hostname); | ||
return this.injectHostnameIntoLocalhostURL( | ||
process.env.AWS_ENDPOINT_URL, | ||
hostname, | ||
); | ||
} | ||
hostname = hostname || 'localhost'; | ||
const proto = TRUE_VALUES.includes(process.env.USE_SSL) ? 'https' : 'http'; | ||
let proto = this.getEndpointProtocol(); | ||
if (process.env.USE_SSL) { | ||
proto = TRUE_VALUES.includes(process.env.USE_SSL) ? 'https' : 'http'; | ||
} else if (this.config.host) { | ||
proto = this.config.host.split('://')[0]; | ||
} | ||
const port = this.getEdgePort(); | ||
@@ -864,3 +972,3 @@ // little hack here - required to remove the default HTTPS port 443, as otherwise | ||
sleep(millis) { | ||
return new Promise(resolve => setTimeout(resolve, millis)); | ||
return new Promise((resolve) => setTimeout(resolve, millis)); | ||
} | ||
@@ -881,14 +989,15 @@ | ||
const regex = /.*:\/\/([^.]+)\.execute-api[^/]+\/([^/]+)(\/.*)?/g; | ||
let newEndpoint = this.localstackEndpoint +'/restapis/$1/$2/_user_request_$3' | ||
if(this.endpointInfo) { | ||
this.endpointInfo = this.endpointInfo.replace(regex, newEndpoint) | ||
const newEndpoint = | ||
this.localstackEndpoint + '/restapis/$1/$2/_user_request_$3'; | ||
if (this.endpointInfo) { | ||
this.endpointInfo = this.endpointInfo.replace(regex, newEndpoint); | ||
} | ||
this.originalDisplay(); | ||
} | ||
}; | ||
newDisplay.bind(plugin) | ||
newDisplay.bind(plugin); | ||
plugin.display = newDisplay; | ||
} | ||
} | ||
patchCustomResourceLambdaS3ForcePathStyle () { | ||
patchCustomResourceLambdaS3ForcePathStyle() { | ||
const awsProvider = this.awsProvider; | ||
@@ -898,3 +1007,3 @@ const patchMarker = path.join( | ||
'.serverless', | ||
'.internal-custom-resources-patched' | ||
'.internal-custom-resources-patched', | ||
); | ||
@@ -904,6 +1013,6 @@ const zipFilePath = path.join( | ||
'.serverless', | ||
awsProvider.naming.getCustomResourcesArtifactName() | ||
awsProvider.naming.getCustomResourcesArtifactName(), | ||
); | ||
function fileExists (filePath) { | ||
function fileExists(filePath) { | ||
try { | ||
@@ -917,5 +1026,5 @@ const stats = fs.statSync(filePath); | ||
function createPatchMarker () { | ||
function createPatchMarker() { | ||
try { | ||
fs.open(patchMarker, 'a').close() | ||
fs.open(patchMarker, 'a').close(); | ||
} catch (err) { | ||
@@ -925,9 +1034,55 @@ return; | ||
} | ||
function patchPreV3() { | ||
const utilFile = customResources.getEntry('utils.js'); | ||
if (utilFile == null) return; | ||
const data = utilFile.getData().toString(); | ||
const legacyPatch = 'AWS.config.s3ForcePathStyle = true;'; | ||
if (data.includes(legacyPatch)) { | ||
createPatchMarker(); | ||
return true; | ||
} | ||
const patchIndex = data.indexOf('AWS.config.logger = console;'); | ||
if (patchIndex === -1) { | ||
return false; | ||
} | ||
const newData = | ||
data.slice(0, patchIndex) + legacyPatch + '\n' + data.slice(patchIndex); | ||
utilFile.setData(newData); | ||
return true; | ||
} | ||
function patchV3() { | ||
this.debug( | ||
'serverless-localstack: Patching V3', | ||
); | ||
const customResourcesBucketFile = customResources.getEntry('s3/lib/bucket.js'); | ||
if (customResourcesBucketFile == null) { | ||
// TODO debugging, remove | ||
this.log( | ||
'serverless-localstack: Could not find file s3/lib/bucket.js to patch.', | ||
); | ||
return; | ||
} | ||
const data = customResourcesBucketFile.getData().toString(); | ||
const oldClientCreation = 'S3Client({ maxAttempts: MAX_AWS_REQUEST_TRY });'; | ||
const newClientCreation = 'S3Client({ maxAttempts: MAX_AWS_REQUEST_TRY, forcePathStyle: true });'; | ||
if (data.includes(newClientCreation)) { | ||
// patch already done | ||
createPatchMarker(); | ||
return; | ||
} | ||
const newData = data.replace(oldClientCreation, newClientCreation); | ||
customResourcesBucketFile.setData(newData); | ||
} | ||
if (fileExists(patchMarker)) { | ||
this.debug("serverless-localstack: Serverless internal CustomResources already patched") | ||
this.debug( | ||
'serverless-localstack: Serverless internal CustomResources already patched', | ||
); | ||
return; | ||
} | ||
const customResourceZipExists = fileExists(zipFilePath) | ||
const customResourceZipExists = fileExists(zipFilePath); | ||
@@ -939,16 +1094,11 @@ if (!customResourceZipExists) { | ||
const customResources = new AdmZip(zipFilePath); | ||
const utilFile = customResources.getEntry('utils.js') | ||
if (utilFile == null) return; | ||
const data = utilFile.getData().toString() | ||
const patch = "AWS.config.s3ForcePathStyle = true;" | ||
if (data.includes(patch)) { | ||
createPatchMarker() | ||
return; | ||
if (!patchPreV3.call(this)) { | ||
patchV3.call(this); | ||
} | ||
const indexPatch = data.indexOf('AWS.config.logger = console;') | ||
const newData = data.slice(0, indexPatch) + patch + '\n' + data.slice(indexPatch) | ||
utilFile.setData(newData) | ||
customResources.writeZip() | ||
createPatchMarker() | ||
this.debug('serverless-localstack: Serverless internal CustomResources patched') | ||
customResources.writeZip(); | ||
createPatchMarker(); | ||
this.debug( | ||
'serverless-localstack: Serverless internal CustomResources patched', | ||
); | ||
} | ||
@@ -955,0 +1105,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
62587
1293
255
16
21