AWS deployment impossible: non-alphanumeric characters not fully escaped in WebSocket routes
See original GitHub issueAWS Lambda WebSocket routes not fully escaped in CloudFormation template
Description
When using serverless for deploying AWS Lambda functions, WebSocket routes with multiple instances of the same non-alphanumeric character result in a CloudFormation template validation error on deployment.
- What did you do?
Added a AWS Lambda function definition to serverless.yml
with a WebSocket route with multiple dashes, like the following:
myFunction:
handler: main.handler
events:
- http: POST /some-api-route
- websocket:
route: some-api-route
- What happened?
The command sls deploy
fails with the message: Error: The CloudFormation template is invalid: Template format error: Resource name someDashapi-routeWebsocketsRoute is non alphanumeric.
Stack trace:
Error: The CloudFormation template is invalid: Template format error: Resource name someDashapi-routeWebsocketsRoute is non alphanumeric.
at provider.request.catch.error (/usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/lib/validateTemplate.js:20:13)
at tryCatcher (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/promise.js:547:31)
at Promise._settlePromise (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/promise.js:604:18)
at Promise._settlePromise0 (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/promise.js:649:10)
at Promise._settlePromises (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/promise.js:725:18)
at _drainQueueStep (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/async.js:93:12)
at _drainQueue (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/async.js:86:9)
at Async._drainQueues (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/async.js:102:5)
at Immediate.Async.drainQueues (/usr/local/lib/node_modules/serverless/node_modules/bluebird/js/release/async.js:15:14)
at runCallback (timers.js:794:20)
at tryOnImmediate (timers.js:752:5)
at processImmediate [as _immediateCallback] (timers.js:729:5)
This template works when running locally with the serverless offline plugin.
- What should’ve happened?
The deployment should have run successfully.
- What’s the content of your
serverless.yml
file?
service: my-service
provider:
name: aws
runtime: python3.6
stage: dev
region: eu-west-1
deploymentBucket:
name: deploymentBucket
websocketsApiRouteSelectionExpression: $request.body.action
functions:
myFunction:
handler: main.handler
events:
- http: POST /some-api-route
- websocket:
route: some-api-route
- What’s the output you get when you use the
SLS_DEBUG=*
environment variable (e.g.SLS_DEBUG=* serverless deploy
)
Error --------------------------------------------------
Error: The CloudFormation template is invalid: Template format error: Resource name someDashapi-routeWebsocketsRoute is non alphanumeric.
at provider.request.catch.error (/usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/lib/validateTemplate.js:20:13)
From previous event:
at AwsDeploy.validateTemplate (/usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/lib/validateTemplate.js:16:85)
From previous event:
at AwsDeploy.BbPromise.bind.then (/usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:119:39)
From previous event:
at Object.aws:deploy:deploy:validateTemplate [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:115:30)
at BbPromise.reduce (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:55)
From previous event:
at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:22)
at PluginManager.spawn (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:510:17)
at AwsDeploy.BbPromise.bind.then (/usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:93:48)
From previous event:
at Object.deploy:deploy [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:89:30)
at BbPromise.reduce (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:55)
From previous event:
at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:22)
at getHooks.reduce.then (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:525:24)
From previous event:
at PluginManager.run (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:525:8)
at variables.populateService.then (/usr/local/lib/node_modules/serverless/lib/Serverless.js:133:33)
at runCallback (timers.js:794:20)
at tryOnImmediate (timers.js:752:5)
at processImmediate [as _immediateCallback] (timers.js:729:5)
From previous event:
at Serverless.run (/usr/local/lib/node_modules/serverless/lib/Serverless.js:120:74)
at serverless.init.then (/usr/local/lib/node_modules/serverless/bin/serverless.js:75:30)
at /usr/local/lib/node_modules/serverless/node_modules/graceful-fs/graceful-fs.js:111:16
at /usr/local/lib/node_modules/serverless/node_modules/graceful-fs/graceful-fs.js:45:10
at FSReqWrap.oncomplete (fs.js:135:15)
From previous event:
at initializeErrorReporter.then (/usr/local/lib/node_modules/serverless/bin/serverless.js:75:8)
at runCallback (timers.js:794:20)
at tryOnImmediate (timers.js:752:5)
at processImmediate [as _immediateCallback] (timers.js:729:5)
From previous event:
at Object.<anonymous> (/usr/local/lib/node_modules/serverless/bin/serverless.js:64:4)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
at startup (bootstrap_node.js:188:16)
at bootstrap_node.js:609:3
Get Support --------------------------------------------
Docs: docs.serverless.com
Bugs: github.com/serverless/serverless/issues
Issues: forum.serverless.com
Your Environment Information ---------------------------
Operating System: linux
Node Version: 8.10.0
Framework Version: 1.60.5
Plugin Version: 3.2.7
SDK Version: 2.2.1
Components Core Version: 1.1.2
Components CLI Version: 1.4.0
Suggested Potential Fix
The following code in lib/plugins/aws/lib/naming.js
appears to be the culprit:
getNormalizedWebsocketsRouteKey(route) {
return route
.replace('$', 'S') // dollar sign
.replace('/', 'Slash')
.replace('-', 'Dash')
.replace('_', 'Underscore')
.replace('.', 'Period');
},
Proposed change:
getNormalizedWebsocketsRouteKey(route) {
return route
.replace(/\$/g, 'S') // dollar sign
.replace(/\//g, 'Slash')
.replace(/-/g, 'Dash')
.replace(/_/g, 'Underscore')
.replace(/\./g, 'Period');
},
Proposed unit tests (lib/plugins/aws/lib/naming.test.js
), under the describe('#getNormalizedWebsocketsRouteKey()')
section at line 252:
it('converts multiple `-` correctly', () => {
expect(sdk.naming.getNormalizedWebsocketsRouteKey('a-longer-path')).to.equal('aDashlongerDashpath');
});
it('converts multiple `-` and `_` correctly', () => {
expect(sdk.naming.getNormalizedWebsocketsRouteKey('a-long_er-path_still')).to.equal('aDashlongUnderscoreerDashpathUnderscorestill');
});
Issue Analytics
- State:
- Created 4 years ago
- Comments:7 (7 by maintainers)
Apologies for the delay, see above for the pull request.
@tom-marsh indeed normalization logic is broken as you point (sorry I missed your point in initial description).
PR that fixes that is definitely welcome!