Serverless error - The CloudFormation template is invalid - during deployment - javascript

When deploying lambdas with serverless, the following error occurs:
The CloudFormation template is invalid: Template format error: Output ServerlessDeploymentBucketName is malformed. The Name field of every Export member must be specified and consist only of alphanumeric characters, colons, or hyphens.
I don't understand what the problem is.
Serverless config file:
service: lambdas-${opt:region}
frameworkVersion: '2'
provider:
name: aws
runtime: nodejs12.x
memorySize: 512
timeout: 10
lambdaHashingVersion: 20201221
region: ${opt:region}
stackName: lambdas-${opt:region}
logRetentionInDays: 14
deploymentBucket:
name: lambdas-${opt:region}
plugins:
- serverless-deployment-bucket
functions:
function1:
handler: function1/index.handler
name: function1-${opt:stage}
description: This function should call specific API on Backend server
events:
- schedule: cron(0 0 * * ? *)
environment:
ENV: ${opt:stage}
function2:
handler: function2/index.handler
name: function2-${opt:stage}
description: Function should be triggered by invocation from backend.
environment:
ENV: ${opt:stage}

I ran into this same problem.
In the serverless.yml I changed service that I had it as lambda_function and put it as lambdaFunction
The error was solved and it deployed correctly.

Most likely your stage name contains an illegal character. Serverless auto-generates a name for your s3 bucket based on your stage name. If you look at the generated template file you will see the full export, which will look something like the following:
"ServerlessDeploymentBucketName": {
"Value": "api-deployment",
"Export": {
"Name": "sls-api_stage-ServerlessDeploymentBucketName"
}
}
The way around this (assuming you don't want to change your stage name) is to explicitly set the output by adding something like this to your serverless config (in this case the illegal character was the underscore)
resources: {
Outputs: {
ServerlessDeploymentBucketName: {
Export: {
Name: `sls-${stageKey.replace('api_', 'api-')}-ServerlessDeploymentBucketName`
}
}
}
}
Unfortunately this has to be done for every export... It is a better option to update your stage name to not include illegal characters

Related

Input undefined when using github actions script and core package

I have a reusable workflow (i.e. triggered by the workflow_call event)
I also have the following input defined in it:
do_something:
description: whether to do something
required: true
type: boolean
default: false
I use the github actions script to invoke a script from a separate file as instructed here, passing the core package as input
- name: checkout the project
uses: actions/checkout#v2
- uses: actions/github-script#v6
id: set-images
with:
script: |
const script = require('./.github/workflows/myscript.js')
console.log(script({core}))
Here is myscript.js
module.exports = ({core}) => {
console.log(core.getBooleanInput['do_something'])
return 0
}
This comes from the documentation of core package found here.
However the specific input seems undefined, here is what gets printed
undefined
0
Why is that?

How to use webdirverio in typescript project, or please provide high level overview of how to refer to types defined in imported packages

This is the specific case I've been working on, below it, further down, is the original more general question.
I'm trying to create a private npm package for e2e testing of a website.
I need to use the webdriverio package.
I want the user to be able to start my executable with a provided configuration, one part of this configuration must be a webdriverio config (actually a subset of it, since I'd like to restrict some options). The other part of the configuration is related to my package: user login name etc.
To achieve this, I've declared my own type and expect the user's argument to conform to it.
But the problem is that when I try to compile the code, which declares that type, I get errors like:
Argument of type '{ … } is not assignable to parameter of type 'RemoteOptions'
Types of property 'logLevel' are incompatible
Type 'string' is not assignable to type 'WebDriverLogTypes | undefined'.
The code, which declares that type is (I left the comments just to demonstrate attempts I'd tried to fix this):
//import { WebdriverIO } from '#wdio/types';
type TestUserConfig = {
//wdioConfig: WebdriverIO,
wdioConfig: {
path: '/wd/hub',
automationProtocol: 'webdriver',
//logLevel: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent',
logLevel: string,
waitforTimeout: number,
capabilities: {
browserName: 'chrome',
},
},
domain: string,
userLogin: string,
userPassword: string,
googleAuthSecret: string,
expectedRole: string,
}
export type {
TestUserConfig,
}
The problem is that if I try to refer to those webdriverio types directly, like:
logLevel: WebDriverLogTypes,
I get errors like Cannot find name 'WebDriverLogTypes'
If I try to import that type like:
import {WebDriverLogTypes} from '#wdio/types';
I ger errors like: Module '"#wdio/types"' has no exported member 'WebDriverLogTypes'
The original question:
Suppose there is a nodejs package (I won't call it module, since I mean a module, but not a module of mine, which is under my control, but a module installed via npm). That package exports a function, which expects certain type as its argument:
type Foo = 'foo';
export default function otherModule(arg: Foo) {}
Now, when I use this module, I want typescript to correctly catch type errors, so that an attempt to compile this TypeScript code throws an error:
import otherModule from 'other-module';
otherModule('bar');
What would be the commonly accepted (probably the best) approach to achieve this?
I've seen some packages have '#types/*' packages too, but I haven't been able to figure out how to use them.
A general approach to use types for other imported libraries/packages etc.:
If the imported library has been developed in JavaScript it, most likely, doesn't have any type definitions out of the box, so in this case there are only these solutions:
check if there is a type definition for this library (usually it may be the '#types/{libraryName}' package or something else, if it's provided in the library docs.
create a type declaration yourself for this library: see the Ambient declarations in the TypeScript docs.
Then import that declaration and use it to refer to types from that library.
For my specific case with webdriverio, I've ended up with the next solution.
Since webdriverio is apparently developed with TypeScript it already has its own type declarations.
So I just looked into the #wdio/types package to see where is that WebDriverLogTypes type had been declared and used that namespace to reference that type:
import type { Options } from '#wdio/types';
type TestUserConfig = {
wdioConfig: {
path: '/wd/hub',
automationProtocol: 'webdriver',
logLevel: Options.WebDriverLogTypes,
waitforTimeout: number,
capabilities: {
browserName: 'chrome',
},
},
domain: string,
userLogin: string,
userPassword: string,
googleAuthSecret: string,
expectedRole: string,
}
export type {
TestUserConfig,
}

i18next - " WebpackError: TypeError: namespaces.forEach is not a function" (hooks)

I'm trying to get i18next to work in my Gatsby project but I keep running into the below error whenever i try to build using yarn build.
From my package.json:
"i18next": "^19.8.2",
"react-i18next": "^11.7.3",
My i18n/index.js file:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
// ...
i18n.use(initReactI18next).init({
fallbackLng: "en",
// have a common namespace used around the full app
ns: ["translations"],
defaultNS: "translations",
wait: true,
useSuspense: false
}, (err, t) => {
i18n.t('en');
});
// load additional namespaces after initialization
i18n.loadNamespaces('translations', (err, t) => {
i18n.t('i18n', { lng: 'en' } );
});
// i18n resource bundles for views
const i18nResourceBundlesViews = [
{
intro: {
en: { ...intro.en },
ja: { ...intro.ja },
},
},
// ...
];
// i18n resource bundles for components
const i18nResourceBundlesComponents = [
{
header: {
en: { ...header.en },
ja: { ...header.ja },
},
},
{
footer: {
en: { ...footer.en },
ja: { ...footer.ja },
},
},
];
// Load i18n resource bundles from each resource object
const getI18nResourceBundles = (resource) => {
const key = Object.keys(resource)[0];
const enBundle = resource[key].en;
const jaBundle = resource[key].ja;
// English translations
i18n.addResourceBundle('en', key, enBundle);
// Japanese translations
i18n.addResourceBundle('ja', key, jaBundle);
};
// i18n resource bundles for views
i18nResourceBundlesViews.forEach((resource) => {
getI18nResourceBundles(resource);
});
// i18n resource bundles for components
i18nResourceBundlesComponents.forEach((resource) => {
getI18nResourceBundles(resource);
});
export default i18n;
The full error message after yarn build
❯ yarn build
yarn run v1.22.5
$ gatsby build
success open and validate gatsby-configs - 0.044s
success load plugins - 0.800s
success onPreInit - 0.016s
success delete html and css files from previous builds - 0.027s
success initialize cache - 0.009s
success copy gatsby files - 0.154s
success onPreBootstrap - 0.020s
success createSchemaCustomization - 0.007s
success source and transform nodes - 1.225s
success building schema - 0.415s
success createPages - 0.021s
success createPagesStatefully - 0.104s
success onPreExtractQueries - 0.002s
success update schema - 0.052s
success extract queries from components - 0.418s
success write out requires - 0.008s
success write out redirect data - 0.005s
warn The icon(./static/favicon/favicon-512.png) you provided to 'gatsby-plugin-manifest' is not square.
The icons we generate will be square and for the best results we recommend you provide a square icon.
success Build manifest and related icons - 0.183s
success onPostBootstrap - 0.192s
⠀
info bootstrap finished - 6.260 s
⠀
warn Browserslist: caniuse-lite is outdated. Please run:
npx browserslist#latest --update-db
success Building production JavaScript and CSS bundles - 19.520s
success Rewriting compilation hashes - 0.010s
success run queries - 20.490s - 6/6 0.29/s
failed Building static HTML for pages - 4.770s
ERROR #95313
Building static HTML failed for path "/404/"
See our docs page for more info on this error: https://gatsby.dev/debug-html
37 | var _this = this;
38 |
> 39 | namespaces.forEach(function (ns) {
| ^
40 | if (!_this.usedNamespaces[ns]) _this.usedNamespaces[ns] = true;
41 | });
42 | }
WebpackError: TypeError: namespaces.forEach is not a function
- context.js:39 ReportNamespaces.addUsedNamespaces
node_modules/react-i18next/dist/es/context.js:39:1
- useTranslation.js:41 useTranslation
node_modules/react-i18next/dist/es/useTranslation.js:41:1
- index.jsx:27 Footer
src/components/theme/Footer/index.jsx:27:38
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
In my Footer/index.jsx where the error originally occurs (line 27):
const { t, i18n } = useTranslation({useSuspense: false});
Any help would be greatly appreciated. Thank you
This issue has been resolved.
Reference including the solution: https://github.com/benji011/portfolio.benjaminlo.io/pull/9#issuecomment-707612060
I think I've managed to pinpoint the two issues you were originally
having. I've uploaded the fixes I've made, please see if it builds for
you. It builds fine for me.
1. React suspense:
i18n appears to use Suspense but this is problematic for Gatsby. See
here.
The fix is quite straightforward and I've added it to the config.
2. The i18ncheck statement: ```const i18nCheck = i18n.languages.toLowerCase().includes('en') ||
i18n.languages.toLowerCase().includes('en-');```
This statement is problematic.
There are two variables that contain the languages.
language, which I think is the current language, and is set to a string: en
languages which is an array of languages. This is set to ['en', 'dev'].
If you want to check for the array languages, then we can't use
toLowerCase() like it was used. It will result in an error as we are
applying toLowerCase() on the entire array and not an element of the
array. toLowerCase() must be used on a string and won't ork on an
array. We would have to loop through the array and then apply
toLowerCase(). I don't think you were wanting to check the array
though as the language, for example 'en', would always be in the
array.
Another issue related to this is that i18n might not have the
property yet, so we need to check that it has the property first.
The best approach, imo, is to just check the language to see if it
is en or en-.
Regarding ESLint and Prettier:
You should use both.
ESLint is a linter and will show code errors. The project already has
an ESLint config, you just need the plugin. There might be a window
that pops up when you open the project, which you must then choose
Allow.
Prettier is a formatter and will format your code e.g. split up a long
line into 3 separate lines

How define lambda function in serverless with inlineCode?

Consider a piece of serverless code:
functions:
MyFunc:
handler: index.handler
name: "my_name"
runtime: nodejs12.x
memorySize: 512
timeout: 30
inlineCode: |
exports.handler = function(event, context) {
console.log("ok");
};
description: description
This leads to pacakge everything in source folder. I can not disable it. Event if I add:
package:
artifact: dummy.zip
Deploy failed because dummy.zip is empty file. But why I need a zip file when specified inlineCode? Is there a way to disable packaging and deploy nodejs function with inlineCode parameter only?
The workaround is to define lambda function deginition as normal cloudformation resource like that:
resources:
Resources:
MyFunc:
Type: AWS::Lambda::Function
Properties:
FunctionName: "my_name"
Handler: index.handler
Runtime: nodejs10.x
Role: !GetAtt LambdaRole.Arn # do not forget to define role by hand :(
Code:
ZipFile: |
exports.handler = function(event, context, callback) {
console.log(event);
const response = {
statusCode: 200,
body: JSON.stringify('Hello Node')
};
callback(null, response);
};
The concept of an inlineCode parameter is supported by AWS::Serverless::Function, but not serverless-framework. The YAML you pasted is not a 1:1 mapping to the AWS::Serverless::Function, it's specific to sls itself.
Store your code in files/directories until the sls team adds support for inlineCode. I didn't see any feature requests for it. I'm sure they'd be glad to get one from you.

AWS: Layer code not found when using "sam invoke local"

I'm working on a sample AWS project that creates two lambda functions. These functions share common code from node_modules which has been placed in a separate layer (specifically AWS::Lambda::LayerVersion, not AWS::Serverless::LayerVersion). I can deploy this code and it works correctly when I test the deployed version.
However, when I try to test the code locally using sam invoke local, the common code is not found. I get this error (I'm trying to use the npm package "axios"):
{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'axios'\nRequire stack:\n- /var/task/get-timezone.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js"}
This is my template.yaml:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Sample
Globals:
Function:
Timeout: 30
Resources:
SampleCommonLayer:
Type: AWS::Lambda::LayerVersion
Properties:
CompatibleRuntimes:
- nodejs12.x
Content: nodejs.zip
Description: Sample Common LayerVersion
LayerName: SampleCommonLayer
GetTimezoneFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: dist/get-timezone
Handler: get-timezone.getTimezone
Runtime: nodejs12.x
Layers:
- !Ref SampleCommonLayer
Events:
GetTimezone:
Type: Api
Properties:
Path: /get-timezone
Method: get
ReverseFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: dist/reverse
Handler: reverse.reverse
Runtime: nodejs12.x
Layers:
- !Ref SampleCommonLayer
Events:
Reverse:
Type: Api
Properties:
Path: /reverse
Method: get
Outputs:
GetTimezoneApi:
Description: "API Gateway endpoint URL for Prod stage for getTimezone function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/get-timezone/"
GetTimezoneFunction:
Description: "getTimezone Lambda Function ARN"
Value: !GetAtt GetTimezoneFunction.Arn
GetTimezoneFunctionIamRole:
Description: "Implicit IAM Role created for getTimezone function"
Value: !GetAtt GetTimezoneFunctionRole.Arn
ReverseApi:
Description: "API Gateway endpoint URL for Prod stage for reverse function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/reverse/"
ReverseFunction:
Description: "reverse Lambda Function ARN"
Value: !GetAtt ReverseFunction.Arn
ReverseFunctionIamRole:
Description: "Implicit IAM Role created for reverse function"
Value: !GetAtt ReverseFunctionRole.Arn
I'm invoking the GetTimezone function like this:
sam local invoke --layer-cache-basedir layer-cache --force-image-build \"GetTimezoneFunction\" --event events/event-timezone.json -d 5858
Nothing ever gets copied into the layer-cache directory, and I'm sure that's part of the problem, but I can't figure out how I'd fix that.
I've searched for answers to this problem, but so far I've only found unanswered questions, or answers that don't match my particular situation.
Most of the somewhat-related questions involve AWS::Serverless::LayerVersion, not AWS::Lambda::LayerVersion. I've tried using Serverless instead, but that hasn't helped.
UPDATE:
If I change...
Layers:
- !Ref SampleCommonLayer
...to...
Layers:
- arn:aws:lambda:us-east-2:xxxxxxxxxxxx:layer:SampleCommonLayer:y
...using an already-deployed layer (where xxxxxxxxxxxx and y are a specific ID and version) then sam local invoke works. But I don't want to use something I have to deploy first, I want to use the latest local not-yet-deployed code.
This is known issue: https://github.com/awslabs/aws-sam-cli/issues/947
Currently the "workaround" is to use the directory of the layer instead of a zip file.

Categories

Resources