Execute ssh shell script from npm command - bash

I'm trying to write an npm script that will execute an ssh shell command. Currently it's working by executing an osascript command to open a Terminal window and run the command.
I'd like to change this to execute the command in the current terminal. The script is including both shelljs and executive. The script ends without anything happening when I use executive. With shelljs I get:
Pseudo-terminal will not be allocated because stdin is not a terminal.
the input device is not a TTY
The command being executed is: ssh -i [ssh-key] -t ubuntu#[ip-address] eval $(base64 -D <<< [command in base64])
The base64 command is sudo docker exec -i -t $(sudo docker ps -aqf "ancestor=' + containerName + '") /bin/bash
If I output the command and copy and paste it, it will work as expected, sshing into a remote machine and running a docker exec command.
If I remove the -t option I don't get the warning messages but there's no output in the console and the script hangs (I assume it's running the command in the background with no output). If I remove the eval ... part I get an output that looks like what you'd see when sshing into a server but without the input terminal.
What can I do to execute this command in the same terminal or in a new tab. If I have to use an osascript command to do this, that's fine as well. I'll be executing this command from the terminal in PhpStorm though.
Edit
Here's the block of code:
var execCommand = 'sudo docker exec -i -t $(sudo docker ps -aqf "ancestor=nginx") /bin/bash';
var buffer = new Buffer(execCommand);
var encoded = buffer.toString('base64');
var cmd = "ssh -i " + this.keyPath + " -t ubuntu#" + ip + " eval $(base64 -D <<< " + encoded + ") ";
shell.exec(cmd);
Edit 2
I can ssh into the machine successfully and get a command prompt but I'm getting a the input device is not a TTY error now when I add the eval command.
var docker_exec = 'sudo docker exec -it $(sudo docker ps -aqf "ancestor=' + containerName + '") /bin/bash';
var encoded = new Buffer(docker_exec).toString('base64');
var sshTerm = spawn('ssh', [
'-i',
this.keyPath,
'ubuntu#' + ip,
'eval',
'eval $(base64 -D <<< ' + encoded + ')'
], {
stdio: 'inherit',
shell: true
});
sshTerm.on('exit', function() {
process.exit(0);
});

I checked and it shelljs.exec is good for non TTY commands. For TTY based command you can use normal spawn method. Below is a sample code that works great for me
var spawn = require('child_process').spawn;
var sshTerm = spawn('ssh', ["vagrant#192.168.33.100", ""], {
stdio: 'inherit'
});
// listen for the 'exit' event
// which fires when the process exits
sshTerm.on('exit', function(code, signal) {
if (code === 0) {
// process completed successfully
} else {
// handle error
}
});

Related

Getting error while trying to run expect script inside bash

Here is my version of script that is first trying to get docker stats container wise but and then moves onto the expect part to start a tester tool to fetch stats by pressing the x key. Script is as follows:
#!/bin/bash
#!/usr/bin/expect -f
docker stats --no-stream --format "{\"container\": \"{{ .Name }}\", \"memory\": { \"raw\": \"{{ .MemUsage }}\", \"percent\": \"{{ .MemPerc }}\"}, \"cpu\": \"{{ .CPUPerc }}\"}"
#docker cp new.sh main:/app/aicore/state_tools/
docker exec main bash -c "cd aicore/state_tools; pwd;
/usr/bin/expect << 'EOF'
set timeout -1
for { set i 0 } { $i < 300000 } { incr i } {
spawn /app/aicore/state_tools/ss_tester
expect "Exit"
send -- "x\r"
expect "press"
send -- "\s03"
sleep 300
}
EOF"
The error I get is as follows:
missing operand at #
in expression " #< 300000 "
(parsing expression " < 300000 ")
invoked from within
"for { set i 0 } { < 300000 } { incr i } {
spawn /app/aicore/state_tools/ss_tester
expect Exit
send -- xr
expect press
send -- s03
sleep 300
}"
Can someone please guide what am I doing wrong in the code?
Looks like a quoting problem. You have quoted the EOF for the here-document, which should prevent substitution on its contents, however that applies after it has been passed to docker. But before it gets to that stage it gets processed by the shell which is running your script, and that will try to substitute the $i before it even gets passed to docker. I would try putting a backslash in front of $i to prevent this, i.e. \$i .

Ampersand to run process in background causes invalid parameters in Bash 5

I have a bash script that runs perfectly well on Bash 3.2. The script contains an ampersand to run a process in the background. However, when I run it in Bash 5.x, it doesn't pass the variables correctly (I get a "SyntaxError: Unexpected end of JSON input"). When I take off the ampersand at the end (of the mgeneratejs line), it executes normally in Bash 5.
#!/bin/bash
#Works on Bash 3.2 on MacOS
#Doesn't work in bash-5.0/5.1
##!/usr/bin/env bash
NUM_ROWS_PER_RUN=5
NUM_RUNS=2
TEMPLATE_STRING='{
name: "$name"
}'
for i in $(seq 1 "$NUM_RUNS")
do
echo "Starting run ${i}"
#If you dont have it, then run "npm install -g mgeneratejs"
mgeneratejs -n "$NUM_ROWS_PER_RUN" "${TEMPLATE_STRING//[$'\r\n ']}" &
done
echo "Waiting"
wait
echo "Finished"
How can I get the process (mgeneratejs) to run in the background when using Bash 5.x?
Bash may or may not be in fault here, but be sure that the problema is in mgeneratejs.
Taking a look mgeneratejs's source code I found this:
if (process.stdin.isTTY) {
var str = argv._[0];
template = _.startsWith(str, '{') ? parseTemplate(str) : parseTemplate(read(str, 'utf8'));
generate();
} else {
template = '';
process.stdin.setEncoding('utf-8');
process.stdin.on('readable', function() {
var chunk = process.stdin.read();
if (chunk !== null) {
template += chunk;
}
});
process.stdin.on('end', function() {
template = JSON.parse(template);
generate();
});
}
If stdin is not a TTY then mgeneratejs assumes that stdin is a pipe, and tries to read from it. This is wrong, they should at least check if the template has been given in the command line args.
I would't recommend that you fix mgeneratejs, but I can recommend you to do this:
function do_run() {
echo "${TEMPLATE_STRING//[$'\r\n ']}" | mgeneratejs -n "$NUM_ROWS_PER_RUN"
}
for i in $(seq 1 "$NUM_RUNS")
do
echo "Starting run ${i}"
#If you dont have it, then run "npm install -g mgeneratejs"
do_run &
done

History command isn't recognized as an internal command in child_process

I'm trying to make a hook for Github in js.
So I need to get the previous command, but child_process doesn't recognize the history command, which runs fine in my windows git bash.
This is the code I have
const { exec } = require("child_process");
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
exec('history 2', (err, res, er) => {
console.log(res)
});
history is no a program (not a binary or a script) but a command builtin into bash. You only can run it with bash — and only interactively:
$ bash -c "history 2"
(no output because it's non-interactive)
In a non-interactive session you have to read the history before using it:
$ bash -c "history -r && history 2"
the previous command
the last command
My advice is to use fc instead of history. With fc you can select one command to show. For example to get the previous command use index -2:
$ bash -c "history -r && fc -ln -2 -2"
the previous command

Sort command in bash script does not work when called from Jenkins

I am trying to execute a shell script on a windows node using Jenkins.
The bash script uses sort -u flag in one of the steps to filter out unique elements from an existing array
list_unique=($(echo "${list[#]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Note - shebang used in the script is #!/bin/bash
On calling the script from command prompt as - bash test.sh $arg1
I got the following error -
-uThe system cannot find the file specified.
I understand the issue was that with the above call, sort.exe was being used from command prompt and not the Unix sort command. To get around this I changed the path variable in Windows System variables and moved \cygwin\bin ahead of \Windows\System32
This fixed the issue and the above call gave me the expected results.
However, When the same script is called on this node using Jenkins, I get the same error again
-uThe system cannot find the file specified.
Jenkins stage calling the script
stage("Run Test") {
options {
timeout(time: 5, unit: 'MINUTES')
}
steps {
script {
if(fileExists("${Test_dir}")){
dir("${Test_dir}"){
if(fileExists("test.sh")){
def command = 'bash test.sh ${env.arg1}'
env.output = sh(returnStdout: true , script : "${command}").trim()
if (env.output == "Invalid"){
def err_msg = "Error Found."
sh "echo -n '" + err_msg + " ' > ${ERR_MSG_FILE}"
error(err_msg)
}
sh "echo Running tests for ${env.output}"
}
}
}
}
}
}
Kindly Help

How to add hook on process kill in bash with a custom bash script?

I have a django server. On start of server, I would like to start docker containers, and on kill of server I would like to stop docker containers
Now I have:
rsAlias.sh:
#/usr/bin/zsh
docker ps --filter name=$(pwd | ~/projectName.js) -aq | xargs docker start
projectName.js:
#!/usr/bin/node
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('' ,(answer) => {
const currentProjectName = answer.split('/').slice(-1)[0]
console.log(currentProjectName);
rl.close();
});
runserver.sh
#!/usr/bin/zsh
~/rsAlias.sh;
source .venv/bin/activate;
./manage.py runserver 0.0.0.0:8000;
and I execute runserver.sh if I want to start server

Resources