AWS Lambda Error: "Cannot find module '/var/task/index'" - javascript

Node.js Alexa Task Issue
I'm currently coding a Node.js Alexa Task via AWS Lambda, and I have been trying to code a function that receives information from the OpenWeather API and parses it into a variable called weather. The relevant code is as follows:
var request = require('request');
var weather = "";
function isBadWeather(location) {
var endpoint = "http://api.openweathermap.org/data/2.5/weather?q=" + location + "&APPID=205283d9c9211b776d3580d5de5d6338";
var body = "";
request(endpoint, function (error, response, body) {
if (!error && response.statusCode == 200) {
body = JSON.parse(body);
weather = body.weather[0].id;
}
});
}
function testWeather()
{
setTimeout(function() {
if (weather >= 200 && weather < 800)
weather = true;
else
weather = false;
console.log(weather);
generateResponse(buildSpeechletResponse(weather, true), {});
}, 500);
}
I ran this snippet countless times in Cloud9 and other IDEs, and it seems to be working flawlessly. However, when I zip it into a package and upload it to AWS Lambda, I get the following error:
{
"errorMessage": "Cannot find module '/var/task/index'",
"errorType": "Error",
"stackTrace": [
"Function.Module._load (module.js:276:25)",
"Module.require (module.js:353:17)",
"require (internal/module.js:12:17)"
]
}
I installed module-js, request, and many other Node modules that should make this code run, but nothing seems to fix this issue. Here is my directory, just in case:
- planyr.zip
- index.js
- node_modules
- package.json
Does anyone know what the issue could be?

Fixed it! My issue was that I tried to zip the file using my Mac's built-in compression function in Finder.
If you're a Mac user, like me, you should run the following script in terminal when you are in the root directory of your project (folder containing your index.js, node_modules, etc. files).
zip -r ../yourfilename.zip *
For Windows:
Compress-Archive -LiteralPath node_modules, index.js -DestinationPath yourfilename.zip

Update to the accepted answer: When this error occurs, it means your zip file is not in the valid form which AWS requires.
If you double click on zip you will find your folder inside that your code file,but lambda wants that when you double click on zip it shoud show direct code files.
To achieve this:
open terminal
cd your-lambda-folder
zip -r index.zip *
Then, upload index.zip to AWS Lambda.

Check that file name and handler name are same:
That means that zip file has bundle.js file that exports handler function:
exports.handler = (event, context, callback) => {//...}

In my case it was because I had the handler file in inner src directory.
I had to change the 'Handler' property within Lambda from:
index.handler
to
src/index.handler

This is probably a permissions issue with files inside your deployment zip.
Try chmod 777 your files before packaging them in a zip file.

In my case the archive contained a folder "src" with index.js file, so I had to put to the handler: "src/index.handler"

In my case I had to replace
exports.handler = function eventHandler (event, context) {
with
exports.handler = function (event, context, callback) {

I got this error when I was using lambci/lambda:nodejs8.10 in windows.
I'd tried all of the solution listed above but none of which could help me deal with my issue(even though the error stack look the same as the question).
Here is my simple solution:
using --entrypoint flag to run a container to find out if the file is mounted into the container. It turns out I may got the share drive issue with my Docker Desktop.
I switched my docker daemon that day before, but everything works fine except this problem.
Anyway, remount my drive to Docker Desktop, you can both use the docker command or just open the Docker Desktop setting to apply.

In my case this was caused by Node running out of memory. I fixed that by adding --memory-size 1500 to my aws lambda create-function ... command.

Related

AWS Lambda fs.readfile issue

I'm packing some files in my lambda package that I need. I've used some example floating around to nearly get it working.
I'm able to verify the path of a file OK
const deviceCert = path.resolve(certType + "-deviceCert.key");
which logs out to
"message": "Resolved path to TEST-deviceCert.key: /var/task/TEST-deviceCert.key"
when I attempt to read the file using
fs.readFile(deviceCert, (err, data) => {
if (err) {
log.error(`Verify deviceCert failure: ${err}`);
responseBody = Helper.buildCORSResponse(502, JSON.stringify({ message: "Unable to locate file required" }));
return callback(null, responseBody);
}
});
I get the following error
Error: ENOENT: no such file or directory, open '/var/task/TEST-deviceCert.key'"
If I can verify the path then why cant I read it?
Any ideas??
Copied from the node.js path.resolve() API documentation:
The path.resolve() method resolves a sequence of paths or path segments into an absolute path.
In other words, resolve concatenates a sequence of strings into one string, formatted as an absolute path. However, it does not check whether or not there is a file at this location. You can use either fs.stat() or fs.access() to verify the presence and access of the file.
eventually confirmed that serverless was packaging the files I needed.
Using fs.readdir I was able to debug the issue and find the path that the packaging process was creating in the Lambda package
/var/task/src//Certs/
Hope this helps someone in the future!!

How to probe if a file was download using Selenium/WebdriverIO

I want to know how I can verify if a file was downloaded using Selenium Webdriver after I click the download button.
Your question doesn't say whether you want to confirm it locally or remotely(like browserstack) . If it is remotely then my answer will be "NO" as you can see that the file is getting downloaded but you can not access the folder. So you wont be able to assert that the file has been downloaded.
If you want to achieve this locally(in Chrome) then the answer is "YES", you can do it something like this:
In wdio.conf.js(To know where it is getting downloaded)
var path = require('path');
const pathToDownload = path.resolve('chromeDownloads');
// chromeDownloads above is the name of the folder in the root directory
exports.config = {
capabilities: [{
maxInstances: 1,
browserName: 'chrome',
os: 'Windows',
chromeOptions: {
args: [
'user-data-dir=./chrome/user-data',
],
prefs: {
"download.default_directory": pathToDownload,
}
}
}],
And your spec file(To check if the file is downloaded or not ?)
const fsExtra = require('fs-extra');
const pathToChromeDownloads = './chromeDownloads';
describe('User can download and verify a file', () =>{
before(() => {
// Clean up the chromeDownloads folder and create a fresh one
fsExtra.removeSync(pathToChromeDownloads);
fsExtra.mkdirsSync(pathToChromeDownloads);
});
it('Download the file', () =>{
// Code to download
});
it('Verify the file is downloaded', () =>{
// Code to verify
// Get the name of file and assert it with the expected name
});
});
more about fs-extra : https://www.npmjs.com/package/fs-extra
Hope this helps.
TL;DR: Unless your web-app has some kind of visual/GUI trigger once the download finishes (some text, an image/icon-font, push-notification, etc.), then the answer is a resounding NO.
Webdriver can't go outside the scope of your browser, but your underlying framework can. Especially if you're using NodeJS. :)
Off the top of my head I can think of a few ways I've been able to do this in the past. Choose as applicable:
1. Verify if the file has been downloaded using Node's File System (aka fs)
Since you're running WebdriverIO, under a NodeJS environment, then you can make use its powerful lib tool-suite. I would use fs.exists, or fs.existsSync to verify if the file is in the expected folder.
If you want to be diligent, then also use fs.statSync in conjunction with fs.exists & poll the file until it has the expected size (e.g.: > 2560 bytes)
There are multiple examples online that can help you put together such a script. Use the fs documentation, but other resources as well. Lastly, you can add said script inside your it/describe statement (I remember your were using Mocha).
2. Use child_process's exec command to launch third-party scripts
Though this method requires more work to setup, I find it more relevant on the long run.
!!! Caution: Apart from launching the script, you need to write a script in a third-party framework.
Using an AutoIT script;
Using a Sikuli script;
Using a TestComplete (not linking it, I don't like it that much), or [insert GUI verification script here] script;
Note: All the above frameworks can generate an .exe file that you can trigger from your WebdriverIO test-cases in order to check if your file has been downloaded, or not.
Steps to take:
create one of the stand-alone scripts like mentioned above;
place the script's .exe file inside your project in a known folder;
use child_process.exec to launch the script and assert its result after it finishes its execution;
Example:
exec = require('child_process').exec;
// Make sure you also remove the .exe from scriptName
var yourScript = pathToScript + scriptName;
var child = exec(yourScript);
child.on('close', function (code, signal) {
if (code!==0) {
callback.fail(online.online[module][code]);
} else {
callback();
}
});
Finally: I'm sure there are other ways to do it. But, your main take-away from such a vague question should be: YES, you can verify if the file has been downloaded if you absolutely must, expecially if this test-case is CRITICAL to your regression-run.

Nodejs Browserify Uncaught TypeError: exists is not a function

I am new to Browserify and trying the following:
I created a node server and trying to get a package called 'openbci' running on the browser.
so I have the following file structure:
Myapp
-...
-public
--app.js
--index.html
--openBCI.js
--...
--javascript
---openBCI
----bundle.js
---...
-node_modules
--openbci
---openBCIBoard.js
--browserify
--...
my app.js file sets the server to serve the public folder
// app.js
var express = require('express');
var app = express();
app.use(express.static('public'));
app.listen(myPort);
then I created the following openBCI.js
// openBCI.js
var OpenBCIBoard = require('openbci').OpenBCIBoard;
exports.OpenBCIBoard = OpenBCIBoard;
and finally launched the browserify command:
$ browserify public/openBCI.js > public/javascript/openBCI/bundle.js
but once called in my index.html file, I got an Uncaught TypeError: exists is not a function at Function.getRoot:
exports.getRoot = function getRoot (file) {
var dir = dirname(file)
, prev
while (true) {
if (dir === '.') {
// Avoids an infinite loop in rare cases, like the REPL
dir = process.cwd()
}
**if (exists(join(dir, 'package.json')) || exists(join(dir, 'node_modules'))) {**
// Found the 'package.json' file or 'node_modules' dir; we're done
return dir
}
if (prev === dir) {
// Got to the top
throw new Error('Could not find module root given file: "' + file
+ '". Do you have a `package.json` file? ')
}
// Try the parent dir next
prev = dir
dir = join(dir, '..')
}
}
It appears that it could not find the original path for the module.
Could you please tell me what is to change? Or if I understood at all how browserify works ? :)
I notice a few things that seem strange about the code.
exists is undefined in JavaScript or node. It appears to be an alias of fs.exists - is that right?
If so, fs.exists is deprecated. Per the documentation, you can achieve the same effect with fs.stat or fs.access. Note however that you should either supply a callback (preferable) or use the Sync version of these methods.
If you are trying to use file system tools in the browser you are going to run into problems because you are attempting to access the server's file system from the browser. There is a plugin, browserify-fs, that gives you an equivalent to fs in the browser. However, this seems to access the browser's local IndexedDB, not the storage on your server.
I would suggest running code that relies on server-side files on the server, rather than in the browser.

AWS Lambda Function is returning "Cannot find module 'index'" yet the handler in the config is set to index

As my title explains I am getting the following error:
{
"errorMessage": "Cannot find module 'index'",
"errorType": "Error",
"stackTrace": [
"Function.Module._resolveFilename (module.js:338:15)",
"Function.Module._load (module.js:280:25)",
"Module.require (module.js:364:17)",
"require (module.js:380:17)"
]
}
I have tried both solutions provided in creating-a-lambda-function-in-aws-from-zip-file and simple-node-js-example-in-aws-lambda
My config currently looks like:
and my file structure is:
and my index.js handler function looks like :
exports.handler = function(event, context) {
What else could be causing this issue aside from what was stated in those two answers above? I have tried both solutions and I have also allocated more memory to the function just incase thats why it couldn't run.
EDIT -
For the sake of trying, I created an even simpler version of my original code and it looked like this:
var Q = require('q');
var AWS = require('aws-sdk');
var validate = require('lambduh-validate');
var Lambda = new AWS.Lambda();
var S3 = new AWS.S3();
theHandler = function (event, context) {
console.log =('nothing');
}
exports.handler = theHandler();
And yet still does not work with the same error?
Try zipping and uploading the contents of the folder lambda-create-timelapse. Not the folder itself.
If this was unclear for anyone else, here are the steps:
Step 1
Navigate to the folder of your project, and open that folder so that you are inside the folder:
Step 2
Select all of the images you want to upload into to Lambda:
Step 3
Right-click and compress the files you have selected:
This will give you a .zip file, which is the file you need to upload to Lambda:
There are a lot of ways to automate this, but this is the manual procedure.
I ran into this problem a few times myself, and this indeed has to do with zipping the folder instead of just the contents like you're supposed to.
For those working from the terminal...
While INSIDE of the directory where the .js files are sitting, run the following:
zip -r ../zipname.zip *
The * is instructing the client to zip all the contents within this folder, ../zipname.zip is telling it to name the file zipname.zip and place it right outside of this current directory.
I had the same problem sometime ago - I reformatted the code.
function lambdafunc1(event, context) {
...
...
...
}
exports.handler = lambdafunc1
The problem occurs when the handler cannot be located in the zip at first level. So anytime you see such error make sure that the file is at the first level in the exploded folder.
To fix this zip the files and not the folder that has the files.
Correct Lambda function declaration can look like this:
var func = function(event, context) {
...
};
exports.handler = func;
You may have other syntax errors that prevent the index.js file from being properly ran. Try running your code locally using another file and using the index.js as your own module.
make sure in your handler following code added
exports.handler = (event, context, callback) => {
...
}
Another reason this can occur is if you don't do an npm install in the folder before packaging and deploying.

Protractor won't take screenshot in Jenkins

I am using the following code to take screenshots (in after each) when a test fails in Protractor:
function failScreenshot() {
var fs = require('fs');
var spec = jasmine.getEnv().currentSpec;
var specName = spec.description.split(' ').join('_');
if (spec.results().passed()) {
return;
} else {
browser.takeScreenshot().then(
function(png) {
var stream = fs.createWriteStream('screenshots/' + specName + '.png');
stream.write(new Buffer(png, 'base64'));
stream.end();
});
}
}
When I am running the tests locally, the screenshot works just as expected. When running the tests via Jenkins, the tests will stop at the first fail and the screenshot is not created. Also, the folders and paths are correct, I have checked them over and over again. My Jenkins version is 1532.1
Any ideeas on how could I solve this issue?
After further documentation I have found the answer. It was a problem with the path. It seems like NODE JS does not read the path as I thought.
The ./ returns the current directory, except in the require() function. When using require(), it reads ./ to the directory of the file in which it was called (obviously, the mistake was here). __dirname is always the directory of the file in which is used.
The code to be used for my path is the following:
__dirname + '/screenshots/' + specName + '.png'
You can also take the screenshots in jenkins by using the mocha-proshot reporter.
It is a npm package which can be downloaded easily and is very easy to setup.

Categories