Using expect to login to amazon server with .PEM file - ssh

I need to do the following:
Log into my amazon server
Change to a specific directory and run a script
The script executes an svn up, I need to be able to pass my username and password to this script.
I've read I might be able to do this with expect? Can I do the login via a shell script and then invoke expect to run the custom script?
Basically, I'm just looking for a good way to do this and would appreciate a pointer in the right direction.

You can use ssh to pass a shell commands to be run on remote Instance.
For example, here's how I check logs on multiple Servers:
#!/bin/bash
nas_servers=(
"ec2-xx-xx-xxx-xxx.ap-xxxx.compute.amazonaws.com"
"ec2-xx-xx-xxx-xxx.ap-xxxx.compute.amazonaws.com"
"ec2-xx-xx-xxx-xxx.ap-xxxx.compute.amazonaws.com"
"ec2-xx-xx-xxx-xxx.ap-xxxx.compute.amazonaws.com"
)
for s in "${nas_servers[#]}"
do
echo "Cheking $s:"
ret=$(ssh -i ~/pem/Key.pem "user#$s" bash << 'EOF'
files=/var/log/syslog*
for f in $files
do
if [[ ${f##*.} = 'gz' ]]; then
cmd=zcat
else
cmd=cat
fi
$cmd $f | egrep -wi 'error|warn|crit|fail'
done
EOF
)
if [[ -z $ret ]]; then
echo "No errors found."
else
echo "$ret"
fi
done

Related

Pass arguments for SQL statement in a shell file from another shell file through ssh command

I am passing command line arguments to a shell file i.e assignRole.sh which contains an SQL command which will use these arguments like below
ssh -o StrictHostKeyChecking=no -T $key < /oracle/oracle_user/makhshif/./assignRole.sh name open_mode >> /oracle/oracle_user/dftest.txt
This gives me error and does not accept arguments of name and open_mode and gives error, but if I execute the statement outside of ssh command like:
/oracle/oracle_user/makhshif/./assignRole.sh name open_mode
This runs fine
What is the problem with ssh command and how should I adjust these parameters so these can be accepted for the shell script assignRole.sh
< /oracle/oracle_user/makhshif/./assignRole.sh
This commands sends a content of that file to stdin. So obviously it can't process variables that you haven't send to remote machine. Just preprocess your script or create a script on remote machine and call it with arguments
Though it's even easier to pass variables like this:
ssh -o StrictHostKeyChecking=no -T $key "var1=$var1 var2=$var2" < /oracle/oracle_user/makhshif/./assignRole.sh name open_mode >> /oracle/oracle_user/dftest.txt
For example my function for executing update scripts on all cluster nodes:
# functions:
ssh_exec(){
local DESCR="$1"; shift
local SCRIPT="$1"; shift
local hosts=("$#")
echo =================================================
echo = $DESCR
echo = Going to execute $SCRIPT...
read -a res -p "Enter 'skip' to skip this step or press Enter to execute: "
if [[ $res = "skip" ]]
then
echo Skipping $SCRIPT...
else
echo Executing $SCRIPT...
for host in "${hosts[#]}"
do
local cur=${!host}
echo Executing $SCRIPT on $host - $cur...
sshpass -p "$rootpass" ssh -o "StrictHostKeyChecking no" root#${cur} \
"ns1=$ns1 ns2=$ns2 search=$search zoo1=$zoo1 zoo2=$zoo2 zoo3=$zoo3 node0=$node0 pass=$pass CURIP=$cur CURHOST=$host bash -s" \
<$SCRIPT >log-$SCRIPT-$cur.log 2>&1
echo Done.
done
echo =================================================
fi
}
Then I use it like this:
read -p "Please check that Solr started successfully and Press [Enter] key to continue..."
#Solr configset and collections:
ssh_exec "Solr configset and collections" script06.sh zoo1 zoo2 zoo3
This command executes script06.sh on 3 servers (zoo1,zoo2,zoo3)
As Sayan said, using < redirects the output of running the assignRole.sh script locally, but you want to execute that script on the remote host, with the arguments.
Pass the whole command as the final argument to ssh, in quotes:
ssh -o StrictHostKeyChecking=no -T $key "/oracle/oracle_user/makhshif/./assignRole.sh name open_mode" >> /oracle/oracle_user/dftest.txt
or split into multiple lines for readability:
ssh -o StrictHostKeyChecking=no -T $key \
"/oracle/oracle_user/makhshif/./assignRole.sh name open_mode" \
>> /oracle/oracle_user/dftest.txt

Running a script when connecting to server with ssh

I use the kitty terminal emulator, so when I connect to a new server, I (usually) need to ad the terminfo (at least, this way it seems to work). To do this I wrote a script. While I was at it, I added a bit of code to add a public key if the user wants it to.
Not really relevant for the question, but here is the code:
#!/bin/bash
host=$1
ip=$(echo $host | cut -d# -f2 | cut -d: -f1)
# Check if it is a unknown host
if [[ -z $(ssh-keygen -F $ip) ]]; then
# Check if there are any ssh-keys
if [ $(ls $HOME/.ssh/*.pub > /dev/null | wc -l) -ne 0 ]; then
keys=$(echo $( (cd $HOME/.ssh/ && ls *.pub) | sed "s/.pub//g" ))
ssh -q -o PubkeyAuthentication=yes -o PasswordAuthentication=no $host "ls > /dev/null 2>&1"
# Check if the server has one of the public keys
if [ $? -ne 0 ]; then
echo "Do you want to add a SSh key to the server?"
while true; do
read -p " Choose [$keys] or leave empty to skip: " key
if [[ -z $key ]]; then
break
elif [[ -e $HOME/.ssh/$key ]]; then
# Give the server a public key
ssh $host "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo \"$(cat $HOME/.ssh/$key.pub)\" >> ~/.ssh/authorized_keys"
break
else
echo "No key with the name \"$key\" found."
fi
done
fi
fi
# Copy terminfo to server
ssh -t $host "echo \"$(infocmp -x)\" > \"\$TERM.info\" && tic -x \"\$TERM.info\" && rm \$TERM.info"
fi
It is not the best code, but it seems to work. Tips are ofcourse welcome.
The problem is that I need to run this script every time I connect te a new remote server (or I need to keep track of which server is new, but that is even worse). Is there a way to run this script every time I connect to a server (the script checks if the ip is a known host).
Or is there an other way to do this? Adding the public keys is nice to have, but not very important.
I hope somone can help,
Thanks!
There is a trick to identify that you are using ssh to login on the target machine:
pgrep -af "sshd.*"$USER |wc -l
The above command will count the user's processes using sshd
You can add the above command in the target machine, to test if you are connected via ssh. Add the above command to your .profile or .bash_profile script in the target machine.
So that only if you login via ssh your script will run initiation script on the target machine when you login/connect.
Sample .bash_profile on target machine
#!/bin/bash
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
if [[ $(pgrep -af "sshd.*"$USER |wc -l) -gt 0 ]]; then
your_init_script
fi

Is it possible to use the "code" command in SSH'ed terminal to open VS Code on local machine with SSH extension?

Something I love about VS Code is that when I am using a terminal in WSL, I can run code file.txt, and it will open that file with VS Code on my local using the WSL remote extension.
Is it possible to do a similar thing with SSH? I.e., if I am SSH'ed into a remote host, is it possible to set things up so that running code file.txt will open VS Code on my local machine, connected via the remote SSH extension to open that file?
I found much better & simple answer thanks to this post.
Simply create new script file named code with below contents & put file under any folder from $PATH. (echo $PATH to see what folders you can use)
#! /usr/bin/env zsh
local max_retry=10
for i in {1..$max_retry}
do
local script=$(echo ~/.vscode-server/bin/*/bin/remote-cli/code(*oc[$i]N))
if [[ -z ${script} ]]
then
echo "VSCode remote script not found"
exit 1
fi
local socket=$(echo /run/user/$UID/vscode-ipc-*.sock(=oc[$i]N))
if [[ -z ${socket} ]]
then
echo "VSCode IPC socket not found"
exit 1
fi
export VSCODE_IPC_HOOK_CLI=${socket}
${script} $# > /dev/null 2>&1
if [ "$?" -eq "0" ]; then
exit 0
fi
done
echo "Failed to find valid VS Code window"
Bash version
#! /bin/bash
max_retry=10
for i in $(seq 1 $max_retry)
do
recent_folder=$(ls ~/.vscode-server/bin/ -t | head -n$i)
script=$(echo ~/.vscode-server/bin/$recent_folder/bin/remote-cli/code)
if [[ -z ${script} ]]
then
echo "VSCode remote script not found"
exit 1
fi
socket=$(ls /run/user/$UID/vscode-ipc-* -t | head -n$i)
if [[ -z ${socket} ]]
then
echo "VSCode IPC socket not found"
exit 1
fi
export VSCODE_IPC_HOOK_CLI=${socket}
${script} $#
if [ "$?" -eq "0" ]; then
exit 0
fi
done
echo "Failed to find valid VS Code window"
Update
Above script doesn't work with recent updates. I had to change first line to
local script=$(echo ~/.vscode-server/bin/*/bin/remote-cli/code(*oc[1]N))
Update2
Original script may fail if recently opened ssh window is closed, yet there is another SSHed window open. I have enhanced the script to enable retrying the command with recent N(default 10) windows.
You shouldn't have to do anything. VSCode automatically sets the path/PATH to the code in the path/PATH environment variable depending on your shell. See this response. You might be overwriting your path/PATH like I was. I was accidentally overwriting path in ~/.cshrc and PATH in ~/.bashrc and was running into the same issue. After fixing it, I can run code on the command line. which code returns the location of the command.
Until I spent time to figure it out, I was using the two methods mentioned below. Both of which worked for me in bash; you can modify it for your shell as you see fit. But really fix your path/PATH rather than using these methods.
Adding location of code to the PATH in ~/.bashrc
export PATH=${VSCODE_GIT_ASKPASS_NODE%/*}/bin:$PATH
OR
Setting alias to code in ~/.bashrc
alias code="${VSCODE_GIT_ASKPASS_NODE%/*}/bin/code"
More on path vs. PATH here and here
Yes, sort of.
From a VSCode terminal run the command
env | grep VSCODE_IPC_HOOK_CLI
then copy-and-paste that line that line with export into your ssh terminal.
After that, you should be able to run code from your ~/.vscode-server/bin/XXX/bin directory.
VSCode terminal
SSH terminal
Update:
You can to automate this with a .bashrc and .profile to place the IPC code into a temp file, and source that when you do your ssh login.
For example, this works for me...
Append this to ~/.bashrc
#
if [ "$VSCODE_IPC_HOOK_CLI" != "" ]; then
cat >$HOME/.vscode_env.sh <<EOF
#
if [ "\$VSCODE_IPC_HOOK_CLI" = "" ]; then
export VSCODE_IPC_HOOK_CLI="$VSCODE_IPC_HOOK_CLI"
alias code="${VSCODE_GIT_ASKPASS_NODE%/*}/bin/code"
fi
EOF
fi
And append this to your ~/.profile
[ -f $HOME/.vscode_env.sh ] && . $HOME/.vscode_env.sh
(There may be more elegant ways. And you still have to start at least 1 terminal in your remote VSCode session.)
this works to me
if [[ -n "$SSH_CLIENT" || -n "$SSH_TTY" ]]; then
local script=$(echo ~/.vscode-server/bin/*/bin/remote-cli/code(*oc[1]N))
if [[ -z ${script} ]]
then
echo "VSCode remote script not found"
exit 1
fi
local socket=$(echo /run/user/$UID/vscode-ipc-*.sock(=oc[1]N))
if [[ -z ${socket} ]]
then
echo "VSCode IPC socket not found"
exit 1
fi
export VSCODE_IPC_HOOK_CLI=${socket}
alias code=${script}
fi
Use the below commands to open a folder or a file on the remote terminal.
Note: vscode-server must be already installed on the remote host (It would be, if you have already connected to it). Also the absolute path has to be specified for the file or folder. Use -n to launch in new window,-r to reuse same window.
code --folder-uri <absolute-path>
code --file-uri <absolute-path-file-name>
Example:
code -r --folder-uri /home/myscripts/src
code -n --file-uri /home/myscripts/src/math/sample.py

ssh to remote server with arguments to run scripts

I have lots of data that needs to be processed, and have access to 3 separate remote servers. The logic is to split up the data crunching among the 3 different servers instead of running on a single one. Note, that all three remote servers are able to point to a single directory, which is where I have the master scripts to process all of the data. The problem I am have is carrying over my arguments when I call different bash scripts.
For example, I have the master script which looks something like:
processing stuff
more stuff
# call the first script
$scriptdir/step1.csh $date $time $name
Within step1.csh, if I have something very simple where I am able to connect to one of the remote servers and output the hostname to a text file, such as:
#!/bin/bash
ssh name#hostname bash -c '
echo `hostname` > host.txt
I get the desired outcome, where 'host.txt' will be the hostname of the desired connected hostname. However, If step1.csh looks like:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh name#hostname bash '
echo `hostname` > host.txt
echo ${mydate} > host.txt
I get the error saying that 'mydate: undefined variable'
Furthermore, If I do something along the lines of:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh name#hostname "python /path/to/somewhere/to/run/${mydate}/and/${mytime}
It still runs on the local, and not remote server. What am I missing here?
So the first part:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh name#hostname bash '
echo `hostname` > host.txt
echo ${mydate} > host.txt
The solution is:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh -T name#hostname << EOF
echo `hostname` > host.txt
echo ${mydate} > host.txt
EOF
However, I am still having issues as in where I try to run a python script on the remote server; it is always ran on the local server.

AIX script hangs when using /dev/null > 2>&1

I am trying to run a script in AIX to execute another script on a remote server. In addition to the remote script i need to send the stdout to /dev/null. The same command works fine on another server but when I run on the current server it hangs, any advice?
su - test -c "rsh testserver /scripts/testme" 2>&1 >/dev/null1
In your comment you write that a menu is presented when the user logins.
Let's say this is done in the .profile file, using echoes and a read command.
When a menu is presented, the read command in the menu code will not be skipped by redirecting the output. The menu still waits for your input and the su command seems to hang.
Can you change your .profile or .bashrc so that it will skip presenting the menu when called using a su command? When this is called during startup, you can look at the returncode of tty. When you use the su command from the commandline, you should look for another solution.
When your root shell is ksh, you can try the following:
if [[ "$(ps -fp $$)" != *"-ksh -c "* ]]; then
echo "Now I should call the Menu"
fi