How to access value of a jenkins groovy variable in shell script for loop - linux

When i am passing value of a variable declared in jenkins Groovy script its value is not retained in for loop which is running on a remote server. Strange thing is i am able to access the same value outside the for loop.
Here is the sample code i am trying to use
#!/usr/bin/env groovy
def config
def COMMANDS_TO_CHECK='curl grep hello awk tr mkdir bc'
pipeline {
agent {
label "master"
}
stages {
stage ('Validation of commands') {
steps {
script {
sh """
#!/bin/bash
/usr/bin/sshpass -p passwrd ssh user#host << EOF
hostname
echo $COMMANDS_TO_CHECK ---> This is printed
for CURRENT_COMMAND in \$COMMANDS_TO_CHECK
do
echo ${CURRENT_COMMAND} ---> Why This is not printed?
echo \${CURRENT_COMMAND} ----> Why This is not printed?
done
hostname
EOF
exit
"""
}
}
}
}
}
Output
[workspace#3] Running shell script
+ /usr/bin/sshpass -p passwrd ssh user#host
Pseudo-terminal will not be allocated because stdin is not a terminal.
illinsduck01
curl grep hello awk tr mkdir bc
illinsduck01
+ exit

You can wrap sh in """ ... """ as below
#!/usr/bin/env groovy
def config
pipeline {
agent {
label "master"
}
stages {
stage ('Validation of commands') {
steps {
script {
sh """#!/bin/sh
/usr/bin/sshpass -p password ssh username#hostname << EOF
COMMANDS_TO_CHECK="curl grep hello awk tr mkdir bc"
hostname
echo \$COMMANDS_TO_CHECK
for CURRENT_COMMAND in \$COMMANDS_TO_CHECK
do
echo \$CURRENT_COMMAND
which \$CURRENT_COMMAND
status=\$?
if [ \${status} -eq 0 ]
then
echo \${CURRENT_COMMAND} command is OK
else
echo "Failed to find the \${CURRENT_COMMAND} command"
fi
done
hostname
EOF
exit
"""
}
}
}
}
}

Related

PowerShell script to SSH to Multiple Linux devices and restart/reboot them

I am comfortable with writing single queries. I am new to writing bash scripts trying to automate the daily stuff. I need help on creating a PowerShell or bash script where I can SSH to multiple Linux devices with same SSH key and then reboot the devices.
I access linux devices manually with the following command in PowerShell
ssh -i C:\<path-to-the-private-key\test.ppk test#XX.X.X.XXX (X - IP Address)
Then I enter the following command
sudo reboot
It asks me to type the password and then restarts the device.
I have 100+ devices that I need to restart.
I can get a list of all IP address in a text file. How can we search for all the IP address in a text file, authenticate with the SSH private key and run the sudo command to restart the device?
Would it also be possible to throw a message if it was not able to restart a device?
Any help would be appreciated.
This is the script that I have.
testreboot.sh
#!/bin/bash
pw="test123"
hosts='IP.txt'
while read -r line; do {
/usr/bin/expect << EOF do
ssh test#"$hosts" 'sudo reboot'
expect "*?assword*"
send "%pw\r"
EOF
}
done < $hosts
IP.txt
XXX.XX.XX.XX
XXX.XX.XX.XX
XXX.XX.XX.XX
XXX.XX.XX.XX
I have Ubuntu 20.04 installed from Windows App Store. I am trying to run the testreboot.sh from PowerShell using the following command and get the following error message.
bash testreboot.sh
testreboot.sh: line 2: $'\r': command not found
testreboot.sh: line 3: $'\r': command not found
testreboot.sh: line 5: $'\r': command not found
testreboot.sh: line 16: syntax error near unexpected token `done'
testreboot.sh: line 16: `done < $hosts'
A better solution to this problem is to use something like Ansible, Chef, or Puppet to solve these multi-server coordination needs.
Here is an example in a shell script using expect to ssh to another server and login:
NOTE: When you use expect in this manner, you need to escape " and $ and
other items. If password has $, it must be escaped.
This is where after logging in and expect see a command prompt
For example:
44 [localhost.localdomain]/home/map%
This is where you would need to add sudo reboot command
-re \"$reg_ex_prompt\" {
}
Test Script:
#!/bin/sh
#
debug=0
exit_val=0
spawn_item="ssh"
destination="user_name#<IP of server to shh>"
reg_ex_prompt='\[%|>|\$|#\] $'
#
# Change -D 0 to -D 1 to debug interactivly
#
expect -D $debug -c "
spawn $spawn_item $destination
set ret 1
set timeout 20
expect {
timeout {
send_user \"Timeout reached!\"
exit \$ret
}
eof {
puts \"End of test connection reached!\"
if { \$ret == 0 } {
puts \"Connection test Successful!\"
puts \"Exiting $destination ...\"
} else {
puts \"Connection Failure!\"
}
exit \$ret
}
\"Connection refused\" {
puts \"ERROR: Trouble connecting to $device_type_parm destination $destination\"
puts \"Aborting...\"
exit \$ret
}
\"Permission denied\" {
puts \"ERROR: User name or password is incorrect for $destination\"
puts \"Aborting...\"
exit \$ret
}
\"Connection reset by peer\" {
puts \"ERROR: Trouble connecting to $destination\"
puts \"Aborting...\"
exit \$ret
}
\"you sure you want to continue connecting\" {
send \"yes\r\"
exp_continue
}
\"assword:\" {
puts \"\r\nSending password\"
send \"password\\\$\r\"
exp_continue
}
\"Choice? \" {
send \"1\r\"
exp_continue
}
\"Q. Quit\" {
send \"q\r\"
exp_continue
}
-re \"$reg_ex_prompt\" {
send \"sudo reboot\r\"
sleep 2
set ret 0
exit \$ret
}
interact
} "
# get the exit value from expect statment above
exit_val=$?

Can I avoid this subshell in a POSIX sh script?

I am trying to comprehend how, if even it can be done, can I avoid subshell?
Is this the only way the code can be written or is there another way?
I tried to use braces { ... }, but it won't pass shellcheck and won't run.
is_running_interactively ()
# test if file descriptor 0 = standard input is connected to the terminal
{
[ -t 0 ]
}
is_tput_available ()
# check if tput coloring is available
{
command -v tput > /dev/null 2>&1 &&
tput bold > /dev/null 2>&1 &&
tput setaf 1 > /dev/null 2>&1
}
some_other_function ()
# so far unfinished function
{
# is this a subshell? if so, can I avoid it somehow?
( is_running_interactively && is_tput_available ) || # <-- HERE
{
printf '%b' "${2}"
return
}
...
}
It is a compound-list, and yes those commands are run in a subshell. To avoid it, use curly braces instead of parentheses:
{ is_running_interactively && is_tput_available; } || ...

Unable to access local variable via a function call through ssh

This the code I,m trying to execute:
#!/bin/bash
set -e -a
err_report() {
echo "Error on line $1"
}
trap 'err_report $LINENO' ERR
IFS=$'\n'
value=($(cat builds.txt))
prevBuild=${value[0]}
prevBuildDir=$prevBuild
currentBuild=${value[1]}
currentBuildDir=$currentBuild
splitPrevBuild=(${prevBuild//./$'\n'})
splitcurrentBuild=(${currentBuild//./$'\n'})
prevBuildSR=${splitPrevBuild[2]}
prevBuildHF=${splitPrevBuild[3]}
prevBuildNum=${splitPrevBuild[4]}
currentBuildSR=${splitcurrentBuild[2]}
currentBuildHF=${splitcurrentBuild[3]}
currentBuildNum=${splitcurrentBuild[4]}
function change {
cd ~/InstallationFiles/${currentBuildSR}/${currentBuildDir}/${currentBuild}extracted
}
change
pwd
ssh -T atao52#kvs-in-hsglap17.in.kronos.com <<-EOF
$(typeset -f)
change
pwd
echo hi
exit
EOF
How to access the variables as currently, it says
cd: /home/atao52/InstallationFiles///extracted: No such file or directory

Execute sudo using expect inside ssh from bash

I want to create a script that automates a installation on multiple linux hosts.
I login to the hosts using ssh keys and inside the login I want to do a sudo, I am trying to use expect, which I have on the stations but I don't have on the server which runs the script.
How do I do this, this is my try, but no luck with it:
#!/bin/bash
ssh user#station04 <<EOF
expect -d -c "
send \"sudo ls\"
expect {
\"password:\" { send '1234'; exp_continue }
\"$user#\"{
send "exit\r"
}
default {exit 1}
}"
EOF
exit
The result:
send: sending "sudo ls" to { exp0 }
expect: does "" (spawn_id exp0) match glob pattern "password:"? no
expect: read eof
expect: set expect_out(spawn_id) "exp0"
expect: set expect_out(buffer) ""
argv[0] = expect argv[1] = -d argv[2] = -c argv[3] =
send "sudo ls\r"
expect {
"password:" { send '1234'; exp_continue }
"#"{
send exitr
}
default {exit 1}
}
set argc 0
set argv0 "expect"
set argv ""
A.K
What about this? <- just make sure of the expected prompts.
#!/bin/bash
expect <<'END'
spawn ssh user#station04
expect "password:"
send "$pw\r"
expect "#"
send "sudo ls\r"
END
I suggest you would use public key authentication for the ssh part, then just use something like:
ssh -t username#server-ip -C "echo sudo-password | /usr/bin/sudo -S ls"
You got the usage of expect not quite right - don't send a command; rather spawn the command and send just its input. So, your script becomes:
ssh … <<EOF
expect -d -c "
spawn sudo ls
expect -nocase password: { send 1234\r }
expect eof
"
exit
EOF

Is it possible to set exit code of 'expect'

The following bash script doesn't work because command 'expect' always return 0 regardless which exit code of the remote script /tmp/my.sh returns.
any idea to make it work? thanks.
#!/usr/bash
user=root
passwd=123456abcd
host=10.58.33.21
expect -c "
spawn ssh -o StrictHostKeyChecking=no -l $user $host bash -x /tmp/my.sh
expect {
\"assword:\" {send \"$passwd\r\"}
eof {exit $?}
}
"
case "$?" in
0) echo "Password successfully changed on $host by $user" ;;
1) echo "Failure, password unchanged" ;;
2) echo "Failure, new and old passwords are too similar" ;;
3) echo "Failure, password must be longer" ;;
*) echo "Password failed to change on $host" ;;
esac
Edited at 10:23 AM 11/27/2013
Thanks for the comments. Let me emphasis the problem once again,
The main script is supposed to run on linux server A silently, during which it invokes another script my.sh on server B unattended. The question is how to get exit code of my.sh?
That's why I cannot leverage ssl_key approach in my case, which requires at least one time configuration.
#!/usr/bin/expect
set user root
set passwd 123456abcd
set host 10.58.33.21
set result_code 255
# exp_internal 1 to see internal processing
exp_internal 0
spawn ssh -o StrictHostKeyChecking=no -l $user $host bash -x /tmp/my.sh && echo aaa0bbb || echo aaa$?bbb
expect {
"assword:" {send "$passwd\r"; exp_continue}
-re "aaa(.*)bbb" {set result_code $expect_out(1,string)}
eof {}
timeout {set result_code -1}
}
switch $result_code {
0 { puts "Password successfully changed on $host by $user" }
1 { puts "Failure, password unchanged" }
2 { puts "Failure, new and old passwords are too similar" }
3 { puts "Failure, password must be longer" }
-1 { puts "Failure, timeout" }
default { puts "Password failed to change on $host" }
}
exit $result_code

Resources