Buildstops not creating file with exec in node js - node.js

I'm running two commands
indexer idx_name --rotate
indexer idx_name --buildstops dict_file 10
Everything is fine when I run these commands from command line. However, when I pass these two commands through my node application using exec, first command works successfully and for second command the dict_file is not getting generated.
I tried some combinations with sudo, but it didn't help. I checked the stdout from both these ways(node and shell) and it looked same.
Here is my node js code:
var exec = require('child_process').exec;
var cmd = 'indexer idx_name --rotate && indexer idx_name --buildstops dict_file 10';
exec(cmd, function(err, stdout, stderr) {
console.log(stdout);
});
Is there something I'm missing ?

Which ever user is running node, will need permission to write dict_file.
Might even find it easier to delete the file, and let it be created by the right user via node (assuming that user can write the the folder)
Sudo could also work, but will need to make sure the user running node, has sudo permissions. Sorting that is definitly outside the remit of stackoverflow.
... do also check you looking in the right place. In your example you dont show a path, so the file dict_file will just be created in the current working directory (not sure how node configures that)

Related

Saving a file in a Snap (Snapcraft) with NodeJS

I am having an issue with creating a new file while my snap is running; example:
1) Snap starts and checks for the config.json file at ./config/config.json
2) If that file is not found (it never is the first time the application runs) it will create it fs.writeFile('./config/config.json', 'My Data', 'utf8', (err) => {....})
3) I Then look for that file later to use it.
I am able to run my node app and all works as expected when using node index.js
I am also able to run using snap try prime/ --devmode and all works.
When running snap try prime/ I get this error in the syslog
Error: ENOENT: no such file or directory, open './config/config.json'
It is erroring at the point of creation.
Any help with this would be awesome!! Thanks in advance.
I was able to solve this by NOT creating and checking for the config files in NodeJS and moving all of that logic to an install hook (https://docs.snapcraft.io/build-snaps/hooks).
So now my Install hook will check for the config file and create it if it's not there, then I allow NodeJS to write to that file later so I can still make all the HTTP requests in NodeJS and not in Bash. Below is my Install hook, don't forget to make it executable.
This file is located at snap/hooks/install
#!/bin/sh
set -e
CONFIG_FILE=$SNAP_COMMON/config.json
if [ ! -f $CONFIG_FILE ]; then
# File Not Found, Create it
echo '{}' > $CONFIG_FILE
fi
Hope this helps someone!

Terminal in React-Electron app

My requirement is to embed a terminal in my React-Electron app wherein all commands which I can run from bash can be run in the embedded terminal too.
Suppose I want to 'npm install' I want it to be possible through my embedded terminal too. Could anyone suggest possible solutions ?
I'm not exactly sure, but I bet you can create a interface with an text input, get the content from it, and use some function of NodeJS to run that content (witch should be a command). Then, just print the result on the screen.
You can use the exec function from "child_process" dependencie, like this.
const { exec } = require("child_process");
exec("ls");
For more details, you can check here: https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback

sqlite3 module cannot open database when started from ubuntu upstart

Working in Ubuntu server 14.04
I have an upstart .conf file in /etc/init for staring my node server. I am using forever. Here is what my script looks like
start on filesystem or runlevel [2345]
expect fork
setuid myUserId
env HOME=/home/myUserId/
env NODE_BIN_DIR=/usr/bin
env NODE_PATH=/usr/lib/nodejs:/usr/lib/node_modules:/usr/share/javascript
script
PATH=$NODE_BIN_DIR:$NODE_PATH:$PATH
echo $PATH
exec forever start -o /home/myUserId/nodeServ/lServer/logs/out.log /home/myUserId/nodeServ/lServer/server.js 1337
end script
But I keep getting this error
Error: SQLITE_CANTOPEN: unable to open database file
error: Forever detected script exited with code: 8
If I run the script from the command line exactly as it is in the conf file it works just fine. No problems. So I think it is a permissions issue. I have set permissions for read write execute on the database directory and the database and still I am unable to read from the file.
I have tried so many different things and I cannot figure out why this is happneing
UPDATE: This problem appears to not be isolated to upstart. I tried staring forever in shell script as well and I get the same errors.
I resolved my issue via workaround. Not using forever and starting node directly from the upstart file (allowing respawn). No issues. This appears to either be a sqlite3 issue or a forever issue.
write this command sudo chown www-data. . in db file directory.
other solution is check file exists or not
ex :
var fs = require("fs");
var exists = fs.existsSync(dbfilepath);

AWS Lambda making video thumbnails

I want make thumbnails from videos uploaded to S3, I know how to make it with Node.js and ffmpeg.
According to this forum post I can add libraries:
ImageMagick is the only external library that is currently provided by
default, but you can include any additional dependencies in the zip
file you provide when you create a Lambda function. Note that if this
is a native library or executable, you will need to ensure that it
runs on Amazon Linux.
But how can I put static ffmpeg binary on aws lambda?
And how can I call from Node.js this static binary (ffmpeg) with AWS Lambda?
I'm newbie with amazon AWS and Linux
Can anyone help me?
The process as outlined by Naveen is correct, but it glosses over a detail that can be pretty painful - including the ffmpeg binary in the zip and accessing it within your lambda function.
I just went through this, it went like this:
Include the ffmpeg static binary in your zipped lambda function package (I have a gulp task to copy this into the /dist every time it builds)
When your function is called, move the binary to a /tmp/ dir and chmod it to give yourself access (Update Feb 2017: it's reported that this is no longer necessary, re: #loretoparisi and #allen's answers).
update your PATH to include the ffmpeg executable (I used fluent-ffmpeg which lets you set two env vars to handle that more easily.
Let me know if more detail is necessary, I can update this answer.
The copy and chmod (step 2) is obviously not ideal.... would love to know if anyone's found a better way to handle this, or if this is typical for this architecture style.
(2nd Update, writing it before the first update b/c it's more relevant):
The copy + chmod step is no longer necessary, as #Allen pointed out – I'm executing ffmpeg in Lambda functions directly from /var/task/ with no trouble at this point. Be sure to chmod 755 whatever binaries before uploading them to Lambda (also as #Allen pointed out).
I'm no longer using fluent-ffmpeg to do the work. Rather, I'm updating the PATH to include the process.env['LAMBDA_TASK_ROOT'] and executing simple bash scripts.
At the top of your Lambda function:
process.env['PATH'] = process.env['PATH'] + "/" + process.env['LAMBDA_TASK_ROOT']
For an example that uses ffmpeg: lambda-pngs-to-mp4.
For a slew of useful lambda components: lambduh.
The below update left in for posterity, but no longer necessary:
UPDATE WITH MORE DETAIL:
I downloaded the static ffmpeg binary here. Amazon recommends booting up an EC2 and building a binary for your use on there, because that environment will be the same as the conditions Lambda runs on. Probably a good idea, but more work, and this static download worked for me.
I pulled only the ffmpeg binary into my project's to-be-archived /dist folder.
When you upload your zip to lambda, it lives at /var/task/. For whatever reason, I ran into access issues trying to use the binary at that location, and more issues trying to edit permissions on the file there. A quick work-around is to move the binary to /tmp/ and chmod permissions on it there.
In Node, you can run shell via a child_process. What I did looks like this:
require('child_process').exec(
'cp /var/task/ffmpeg /tmp/.; chmod 755 /tmp/ffmpeg;',
function (error, stdout, stderr) {
if (error) {
//handle error
} else {
console.log("stdout: " + stdout)
console.log("stderr: " + stderr)
//handle success
}
}
)
This much should give you an executable ffmpeg binary in your lambda function – but you still need to make sure it's on your $PATH.
I abandoned fluent-ffmpeg and using node to launch ffmpeg commands in favor of just launching a bash script out of node, so for me, I had to add /tmp/ to my path at the top of the lambda function:
process.env.PATH = process.env.PATH + ':/tmp/'
If you use fluent-ffmpeg, you can set the path to ffmpeg via:
process.env['FFMPEG_PATH'] = '/tmp/ffmpeg';
Somewhat related/shameless self-plug: I'm working on a set of modules to make building Lambda functions out of composable modules easier under the name Lambduh. Might save some time getting these things together. A quick example: handling this scenario with lambduh-execute would be as simple as:
promises.push(execute({
shell: "cp /var/task/ffmpeg /tmp/.; chmod 755 /tmp/ffmpeg",
})
Where promises is an array of promises to be run.
I created a GitHub repo that does exactly this (as well as resizes the video at the same time). Russ Matney's answer was extremely helpful to make the FFmpeg file executable.
I am not sure what custom mode library you would use for the ffmpeg task; nevertheless the steps to accomplish that are the same.
Create a separate directory for your lambda project
Run npm install <package name> inside that directory ( this would automatically put in place the node_modules and appropriate files )
Create index.js file in the lambda project directory then use the require(<package-name>) and perform your main task for video thumbnails creation
Once you are done, you can zip the lambda project folder and upload it I'm AWS management console and configure the index file and handler.
Rest of configurations follow the same process like IAM Execution Role, Trigger, Memory and Timeout specification etc.
I got this working without moving it to /tmp. I ran chmod 755 on my executable and then it worked! I had problems when I previously set it to chmod 777.
At the time I'm writing, as well described above there is no need anymore to copy binaries from current folder, that is the var/task or the process.env['LAMBDA_TASK_ROOT'] folder to the /tmp folder.
So it is just necessary to do
chmod 755 dist/ff*
if you have your ffmpeg and ffprobe binaries there.
By the way, previously my 2 cents solution that wasted 2 days time was this
Configure : function(options, logger) {
// default options
this._options = {
// Temporay files folder for caching and modified/downloaded binaries
tempDir : '/tmp/',
/**
* Copy binaries to temp and fix permissions
* default to false - since this is not longer necessary
* #see http://stackoverflow.com/questions/27708573/aws-lambda-making-video-thumbnails/29001078#29001078
*/
copyBinaries : false
};
// override defaults
for (var attrname in options) { this._options[attrname] = options[attrname]; }
this.logger=logger;
var self=this;
// add temporary folder and task root folder to PATH
process.env['PATH'] = process.env['PATH'] + ':/tmp/:' + process.env['LAMBDA_TASK_ROOT']
if(self._options.copyBinaries)
{
var result = {}
execute(result, {
shell: "cp ./ffmpeg /tmp/.; chmod 755 /tmp/ffmpeg", // copies an ffmpeg binary to /tmp/ and chmods permissions to run it
logOutput: true
})
.then(function(result) {
return execute(result, {
shell: "cp ./ffprobe /tmp/.; chmod 755 /tmp/ffprobe", // copies an ffmpeg binary to /tmp/ and chmods permissions to run it
logOutput: true
})
})
.then(function(result) {
self.logger.info("LambdaAPIHelper.Configure done.");
})
.fail(function(err) {
self.logger.error("LambdaAPIHelper.Configure: error %s",err);
});
} //copyBinaries
}
helped by the good lambduh module:
// lambuh & dependencies
var Q = require('q');
var execute = require('lambduh-execute');
As described here and confirmed by module author now this can be considered not needed, by the way it's interesting to have a well understanding of the lambda runtime (the machine) environment that is well described in Exploring the Lambda Runtime environment.
I just went through the same issues as described above and ended up moving with the same concept of moving my scripts requiring execution to the /tmp directory.
var childProcess = require("child_process");
var Q = require('q');
Code I used is below with promises:
.then(function(result) {
console.log('Move shell ffmpeg shell script to executable state and location');
var def = Q.defer();
childProcess.exec("mkdir /tmp/bin; cp /var/task/bin/ffmpeg /tmp/bin/ffmpeg; chmod 755 /tmp/bin/ffmpeg",
function (error, stdout, stderr) {
if (error) {
console.log("error: " + error)
} else {
def.resolve(result);
}
}
)
return def.promise;
})
In order for the binary to be directly executable on AWS Lambda (without first having to copy to /tmp and chmod), you need to ensure the binary has executable permission when it is added to the ZIP file.
This is problematic on Windows because Windows doesn't recognize Linux binaries. If you're using Windows 10, use the Ubuntu Bash shell to create the package.
I created a Node.js function template specifically for this purpose here. It allows you to deploy one or more binaries to Lambda, then execute an arbitrary shell command and capture the output.

Detect if have got sudo right info

Is it possible to detect that I have the right sudo when I run
node app.js
I hope that when I run the command
sudo node app.js
it will tell me that the app.js node is running with the right sudo.
I can't ensure this is correct since I currently have no way of testing it but if I remember correctly you should be able to use the getuid() function from the process package (Documentation).
(Note: This only works on POSIX platforms, which means no Windows)
This should return "root" when you run the command with super user permissions.
IMPORTANT You should never run a webserver like node with super user permissions. If you need the permissions for some setup work you should revert the granted root permissions by doing something like this at the end of your initialization work:
var uid = parseInt(process.env.SUDO_UID);
if (uid) process.setuid(uid);
I found the accepted answer confusing. Coming from that, and based on some personal testing, the following code works:
function isRoot() {
return !!process.env.SUDO_UID; // SUDO_UID is undefined when not root
}
as well as this:
function isRoot() {
return !process.getuid(); // getuid() returns 0 for root
}

Resources