Shell script to login to remote VM and run commands from remote VM - linux

I need to login to a remote VM and run some commands. I am able to login successfully but echo command does not return list of files from the remote VM instead it returns output from local machine. Can anyone suggest how can I achieve this?
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<EOF
cd /var;
echo "$(ls)";
EOF
exit

It worked after removing echo. PFB solution:
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1 << EOT
cd /var;
ls -ltr;
EOT
exit

You have to escape $ in EOF sequence like this:
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<EOF
cd /var;
echo "\$(ls)";
EOF
Or escape whole EOF sequence like this:
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<'EOF'
cd /var;
echo "$(ls)";
EOF

alternatively, if you quote the marker, then substitution doesn't take place in the local shell:
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<'EOF'
cd /var;
echo "$(ls)";
EOF
exit

Related

Unable to use EOT inside if in shell script

Unable to use End of transmission (EOT) with ssh command inside if, it gives compilation error. I have tried using <<-EOT and <<<EOT but nothing worked. Can anyone suggest a fix for this?
#!bin bash
if [ -z "$2" ];
then
rsync -a abc.tgz root#$1:/var/folder1
echo "Done upload"
# Change permissions of agent image and create image configuration
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<EOT
chmod 644 /var;
echo "image.id=$containerSha" > /var;
EOT
else
rsync -a abc.tgz root#$1:/var
echo "Upload done"
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<EOT
cd /var;
sshpass -p '$3' rsync -a abc.tgz root#$2:/var;
sshpass -p '$3' ssh root#$2 'chmod 777 /var/*; ls -ltr';
EOT
fi
exit
Running your script through Shellcheck reveals these errors (along with a misshaped shebang line):
Line 12:
EOT
^-- SC1039 (error): Remove indentation before end token
(or use <<- and indent with tabs).
Line 21:
EOT
^-- SC1039 (error): Remove indentation before end token
(or use <<- and indent with tabs).
Line 23:
exit
^-- SC1072 (error): Here document was not correctly terminated.
Fix any mentioned problems and try again.
The EOT markers must not be indented.
I just had this issue and removing indents will solves the problem:
Instead of:
...
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<EOT
chmod 644 /var;
echo "image.id=$containerSha" > /var;
EOT
else
...
You can try:
...
ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=no root#$1<<EOT
chmod 644 /var;
echo "image.id=$containerSha" > /var;
EOT
else
...
If I'm not mistaken, an EOT is the character with the numeric value 4. If you define (for better readability) in your code
eot=$'\004'
you can later use ${eot} to denote your end-of-transmission.
UPDATE: My answer here refers to the problem of representing the end-of-transmission character in a bash program. As AKX reasonably argued in his comment, the real question is unrelated to end-of-transmission, but on how to mark the end of a here-document.

BASH with sshpass send same command to multiple servers based on list of servers? [duplicate]

This question already has answers here:
Loop through an array of strings in Bash?
(21 answers)
Closed 2 years ago.
Hi I have the following "script" below which works fine.
#!/bin/bash
TARGET="vm-windows-server01.local"
TARGET_USER="administrator"
TARGET_PASSWORD="Qwerty"
TARGET2="vm-linux-server01.local"
TARGET_USER2="root"
TARGET_PASSWORD2="Qwerty123"
#Windows server shutdown
sshpass -p $TARGET_PASSWORD ssh -o stricthostkeychecking=no $TARGET_USER#$TARGET 'shutdown /s /c "Shutting down"'
#Linux server shutdown
sshpass -p $TARGET_PASSWORD2 ssh -o stricthostkeychecking=no $TARGET_USER2#$TARGET2 'shutdown 3 "Shutting down"'
Now instead of copying TARGET variables for over 50 servers along with 50 more lines of the sshpass
Can something like this below be done? Please be advised its bogus code just to give the idea what i want. I'm new to bash so be gently :-)
#!/bin/bash
WINDOWS_SERVERS="
vm-windows-server01.local,
vm-windows-server02.local,
vm-windows-server03.local"
WINDOWS_USER="administrator"
WINDOWS_PASSWORD="Qwerty"
LINUX_SERVERS="
vm-linux-server01.local,
vm-linux-server02.local,
vm-linux-server03.local"
LINUX_USER="root"
LINUX_PASSWORD="Qwerty123"
#Windows server shutdown
sshpass -p $WINDOWS_PASSWORD ssh -o stricthostkeychecking=no $WINDOWS_USER#$WINDOWS_SERVERS 'shutdown /s /c "Shutting down"'
#Linux server shutdown
sshpass -p $LINUX_PASSWORD ssh -o stricthostkeychecking=no $LINUX_USER#$LINUX_SERVERS 'shutdown 3 "Shutting down"'
Basically runs the sshpass for all the hosts in the list.
If you are unsure about the availability of Bash, or another shell which knows about arrays; you can adapt your code to iterate over your server lists with the POSIX available grammar (no array):
#!/usr/bin/env sh
WINDOWS_SERVERS="
vm-windows-server01.local,
vm-windows-server02.local,
vm-windows-server03.local"
WINDOWS_USER="administrator"
WINDOWS_PASSWORD="Qwerty"
LINUX_SERVERS="
vm-linux-server01.local,
vm-linux-server02.local,
vm-linux-server03.local"
LINUX_USER="root"
LINUX_PASSWORD="Qwerty123"
echo "$WINDOWS_SERVERS" | {
IFS=$(printf '\t\n, ')
while read -r windows_host || [ "$windows_host" ]
do
sshpass -p "$WINDOWS_PASSWORD" ssh -o stricthostkeychecking=no "$WINDOWS_USER#$windows_host" 'shutdown /s /c "Shutting down"'
done
}
echo "$LINUX_SERVERS" | {
IFS=$(printf '\t\n, ')
while read -r linux_host || [ "$linux_host" ]
do
sshpass -p "$LINUX_PASSWORD" ssh -o stricthostkeychecking=no "$LINUX_USER#$linux_host" 'shutdown 3 "Shutting down"'
done
}
But if you have bash, zsh or ksh 93+ who supports arrays, your script syntax is simpler and easier to maintain:
#!/usr/bin/env bash
WINDOWS_SERVERS=(
'vm-windows-server01.local'
'vm-windows-server02.local'
'vm-windows-server03.local'
)
WINDOWS_USER='administrator'
WINDOWS_PASSWORD='Qwerty'
LINUX_SERVERS=(
'vm-linux-server01.local'
'vm-linux-server02.local'
'vm-linux-server03.local'
)
LINUX_USER='root'
LINUX_PASSWORD='Qwerty123'
for windows_host in "${WINDOWS_SERVERS[#]}"
do
sshpass -p "$WINDOWS_PASSWORD" ssh -o stricthostkeychecking=no "$WINDOWS_USER#$windows_host" 'shutdown /s /c "Shutting down"'
done
for linux_host in "${LINUX_SERVERS[#]}"
do
sshpass -p "$LINUX_PASSWORD" ssh -o stricthostkeychecking=no "$LINUX_USER#$linux_host" 'shutdown 3 "Shutting down"'
done

how to use value that is calculated inside ssh

I have linux script like below:
sshpass -p "pwd" ssh -tt user << 'EOF'
cd /directory
file=$(ls -1t | head -1)
exit
EOF
How to use the file parameter outside ssh. That is after EOF statement.
I think that you have to work with the output of the SSH command to capture it into a local variable.
This could be a viable solution (tried with obviously different parameters locally, OS Ubuntu 17.04):
CMD=`cat <<EOF
cd /directory
ls -1t | head -1
EOF`
FILE=`sshpass -p "pass" ssh -t user#host -o LogLevel=QUIET "$CMD"`
echo "$FILE"

Skip password prompt using sh script

I have script that inputs the list of server ips and ssh using pem key to run commands but some servers have password i want to skip that so that it take the next ip ?
Below is the script:
cat privateiptest-ss | while read LINE
do
echo $LINE >> ss-prodcht1.txt
stackname=$LINE
ssh -o "PasswordAuthentication=no" -o "StrictHostKeyChecking no" -t -t -i key.pem ec2-user#$stackname "bash -s" < sh.sh
done
If you use the option BatchMode=yes with ssh, i.e.
ssh -o "BatchMode=yes" -o "StrictHostKeyChecking=no" -t -t -i key.pem ec2-user#$stackname "bash -s" < sh.sh
then ssh will never prompt for a password. For servers that do require a password, ssh will fail.

Automate SSH Configuration for new Hadoop cluster

Guessing this has been done many times, but I could not find a clean answer, so I am appealing to your expertise for a better solution:
Objective: I am setting up a moderate sized RHEL Hadoop cluster and want to automate the configuration of SSH connectivity between all nodes. On the first node I have a list of all of the IPs in the file 'remote_ips', and I have the hduser password in the file 'hduser_pw' (chmod 600).
Step 1) Create "hduser_pw" password file on each host
for x in $(cat remote_ips); do sshpass -p$(cat hduser_pw) ssh -o StrictHostKeyChecking=no hduser#$x "echo $(cat hduser_pw) > hduser_pw; chmod 600 hduser_pw"; done
Step 2) Generate RSA keys for each node in cluster:
for x in $(cat remote_ips); do sshpass -p$(cat hduser_pw) ssh -o StrictHostKeyChecking=no hduser#$x "echo -e 'y'| ssh-keygen -t rsa -N \"\"
"; done
Step 3) Copy the file 'remote_ips' to each node in the cluster:
for x in $(cat remote_ips); do sshpass -p$(cat hduser_pw) scp -o StrictHostKeyChecking=no remote_ips hduser#$x:~; done
Step 4) For each node, copy the RSA public key to "authorized_keys" in every other node:
for x in $(cat remote_ips); do sshpass -p$(cat hduser_pw) ssh -o StrictHostKeyChecking=no hduser#$x 'for y in $(cat remote_ips); do cat /home/hduser/.ssh/id_rsa.pub | sshpass -p$(cat hduser_pw) ssh -o StrictHostKeyChecking=no hduser#$y '\''cat >> .ssh/authorized_keys'\'' ; done '; done
Is there a better way to do this? Really appreciate your help.
EDIT: Here are my revisions:
I incorporated the feedback from #janos and #likewhoa --> I handled the UUOC with redirection, looped across each IP, removed any pwds from the shell history with variables, etc. Thanks so much!
hduser_pw=$(< hduser_pw)
remote_ips=$(< remote_ips)
for x in $remote_ips; do
echo "Create hduser_pw password file on node: ${x}"
sshpass -p$hduser_pw scp -o StrictHostKeyChecking=no hduser_pw hduser#$x:~
echo "chmod 600 hduser_pw on node: ${x}"
sshpass -p$hduser_pw ssh -o StrictHostKeyChecking=no hduser#$x "chmod 600 hduser_pw"
echo "Generate RSA keys for: ${x}"
sshpass -p$hduser_pw ssh -o StrictHostKeyChecking=no hduser#$x "echo y | ssh-keygen -f ~/.ssh/id_rsa -t rsa -N \"\""
echo "SCP the file remote_ips to node: ${x}"
sshpass -p$hduser_pw scp -o StrictHostKeyChecking=no remote_ips hduser#$x:~
done
for x in $remote_ips; do
for y in $remote_ips; do
echo "ssh-copy-id from node ${x} to node ${y}:"
sshpass -p$hduser_pw ssh -o StrictHostKeyChecking=no hduser#$x "sshpass -p${hduser_pw} ssh-copy-id -i ~/.ssh/id_rsa.pub hduser#${y} -o StrictHostKeyChecking=no";
done
done
Instead of running $(cat hduser_pw) and $(cat remote_ips) multiple times,
it would be better to run them only once and, save in variables and reuse.
For example:
hduser_pw=$(cat hduser_pw)
remote_ips=$(cat remote_ips)
# Step 1) Create "hduser_pw" password file on each host
for x in $remote_ips; do
sshpass -p$hduser_pw ssh -o StrictHostKeyChecking=no hduser#$x "echo $hduser_pw > hduser_pw; chmod 600 hduser_pw"
done
Can you spot the security problem? The echo $hduser_pw will be saved in the shell history, and may also be visible in ps printings. It's better to avoid it. Instead of this:
ssh server "echo $hduser_pw > hduser_pw; chmod 600 hduser_pw"
You can do like this:
ssh server "cat > hduser_pw; chmod 600 hduser_pw" < hduser_pw
That's a bit hacky and may be confusing.
A simpler option is to scp and then ssh (for the chmod):
scp hduser_pw server:
ssh server "chmod 600 hduser_pw"
Other simplifications:
Instead of echo -e 'y' | ... you can simplify to echo y | ...
Instead of the messy Step 4, take a look into ssh-copy-id if it's available (usually it is in Linux systems)
First off UUOC, you really should use a while loop and re-directions instead of CAT.
Use this instead for the following steps which merges all steps into one big while loop.
while read ips; do sshpass -p$(<hduser_pw) ssh -o StrictHostKeyChecking=no hduser#$ips "echo $(<hduser_pw) > hduser_pw; chmod 600 hduser_pw"; sshpass -p$(<hduser_pw) ssh -o StrictHostKeyChecking=no hduser#$ips ssh-keygen -f ~/.ssh/id_rsa -t rsa -N \"\"";sshpass -p$(<hduser_pw) scp -o StrictHostKeyChecking=no remote_ips hduser#$ips:;done <remote_ips
I'll let you fix Step 4 on your own. GL!
Few pointers.
Use while loops when reading through lines
ssh-keygen -f ~/.ssh/somekey to avoid 'echo y | ssh-keygen ...'
Use redirect '
Good luck! Perhaps this is best if you use some kind of Configuration Management tools to automate this and more.

Resources