-2

Hello People of the world,

I am trying to write a script that will allow user to failover apps between sites in bash.

Our applications are controlled by Pacemaker and I thought I would be able to write a function that would take in the necessary variables and act. Stop on one site, start on another. Once I have ssh'd to the remote machine, I am unable to get the value of the grep/awk command back for the status of the application in PCS.

I am encountering a few issues, and have tried answers from stackoverflow and other sites.

  1. I send the ssh command to /dev/null 2>&1 as banners pop up on screen that unix admin have on the local user and -q does not deal with it - Does this stop anything being returned?
  2. when using awk '{print \\\\\\$4}' in the code, I get a "backslash not last character on line" error
  3. To get round this, I tried result=$(sudo pcs status | grep nds_$resource), however this resulted in a password error on sudo
  4. I have tried >/dev/tty and >$(tty)
  5. I tried to not suppress the ssh (remove /dev/null 2>&1) and put the output in variable at function call, removing the awk from the sudo pcs status entry.
result=$(pcs_call "$site1" "1" "2" "disable" "pmr")
echo $result | grep systemd 

This was OK, but when I added | awk '{print \\\$4}' I then got the fourth word in the banner.

Any help would be appreciated as I have been going at this for a few days now.

I have been looking at this answer from Bruno, but unsure how to implement as I have multiple sudo commands.

Below is my strip down of the function code for testing on one machine;

site1=lon
site2=ire


function pcs_call()
{
 site=$1
 serverA=$2
 serverB=$3
 activity=$4
 resource=$5

ssh -tt ${site}servername0${serverA}  <<SSH > /dev/null 2>&1
         sudo pcs resource ${activity} proc_${resource}
         sleep 10
         sudo pcs status  | grep proc_$resource | awk '{print \\\$4}' | tee $output
         exit
SSH
echo $output
}

echo ====================================================================================
echo Shutting Down PMR in $site1
pcs_call "$site1" "1" "2" "disable" "pmr"
Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
Red_badger
  • 119
  • 1
  • 15

1 Answers1

0

I'd say start by pasting the whole thing into ShellCheck.net and fixing errors until there are no suggestions, but there are some serious issues here shellcheck is not going to be able to handle alone.

  1. > /dev/null says "throw away into the bitbucket any data that is returned. 2>&1 says "Send any useful error reporting on stderr wherever stdout is going". Your initial statement, intended to retrieve information from a remote system, is immediately discarding it. Unless you just want something to occur on the remote system that you don't want to know more about locally, you're wasting your time with anything after that, because you've dumped whatever it had to say.
  2. You only need one backslash in that awk statement to quote the dollar sign on $4.
  3. Unless you have passwordless sudo on the remote system, this is not going to work out for you. I think we need more info on that before we discuss it any deeper.
  4. As long as the ssh call is throwing everything to /dev/null, nothing inside the block of code being passed is going to give you any results on the calling system.
  5. In your code you are using $output, but it looks as if you intend for tee to be setting it? That's not how that works. tee's argument is a filename into which it expects to write a copy of the data, which it also streams to stdout (tee as in a "T"-joint, in plumbing) but it does NOT assign variables.

(As an aside, you aren't even using serverB yet, but you can add that back in when you get past the current issues.)

At the end you echo $output, which is probably empty, so it's basically just echo which won't send anything but a newline, which would just be sent back to the origin server and dumped in /dev/null, so it's all kind of pointless....

Let's clean up

sudo pcs status | grep proc_$resource | awk '{print \\\$4}' | tee $output

and try it a little differently, yes?

First, I'm going to assume you have passwordless sudo, otherwise there's a whole other conversation to work that out.

Second, it's generally an antipattern to use both grep AND awk in a pipeline, as they are both basically regex engines at heart. Choose one. If you can make grep do what you want, it's pretty efficient. If not, awk is super flexible. Please read the documentation pages on the tools you are using when something isn't working. A quick search for "bash man grep" or "awk manual" will quickly give you great resources, and you're going to want them if you're trying to do things this complex.

So, let's look at a rework, making some assumptions...

function pcs_call() {
  local site="$1" serverA="$2" activity="$3" resource="$4" # make local and quotes habits you only break on purpose
  ssh -qt ${site}servername0${serverA} "
    sudo pcs resource ${activity} proc_${resource}; sleep 10; sudo pcs status; 
  " 2>&1 | awk -v resource="$resource" '$0~"proc_"resource { print $4 }'
}

pcs_call "$site1" 1 disable pmr # should print the desired field

If you want to cath the data in a variable to use later -

var1="$( pcs_call "$site1" 1 disable pmr )"

addendum

Addressing your question - use $(seq 1 10) or just {1..10}.

ssh -qt chis03 '
    for i in {1..10}; do sudo pcs resource disable ipa $i; done;
    sleep 10; sudo pcs status;
' 2>&1 | awk -v resource=ipa '$0~"proc_"resource { print $2" "$4 }'

It's reporting the awk first, because order of elements in a pipeline is "undefined", but the stdout of the ssh is plugged into the stdin of the awk (and since it was duped to stdout, so is the stderr), so they are running asynchronously/simultaneously.

Yes, since these are using literals, single quotes is simpler and effectively "better". If abstracting with vars, it doesn't change much, but switch back to double quotes.

# assuming my vars (svr, verb, target) preset in the context
ssh -qt $svr "
    for i in {1..10}; do sudo pcs resource $verb $target \$i; done;
    sleep 10; sudo pcs status;
" 2>&1 | awk -v resource="$target" '$0~"proc_"resource { print $2" "$4 }'

Does that help?

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
  • Hi Paul, Thank you for taking the time to read through this. – Red_badger Feb 08 '23 at 16:52
  • The Solution worked 1) Yes, i thought the /dev/null would suppress ALL outputs, however i was seeing the text from the remote shell. This because i was the EOF (SSH in my script) using this is also why i had to have \\\$4 in awk. 2) Thank you for the info on tee, i would see that i was creating files in the folder i was running the script from with the script output. 3) thanks for the advice on grep/awk - that is a way i have used that command for years, i will look into improving my awk. 4) yep sudo was passwordless 5) serverB is in another part of the script not posted. – Red_badger Feb 08 '23 at 17:03
  • Hi Paul, Does this method - as opposed to heredoc, allow for this command; ``` for i in `seq 1 10`; do sudo pcs resource disable ipa \$i; done; sleep 10; sudo pcs status; " 2>&1 | awk -v resource=ipa '$0~"proc_"resource { print $2" "$4 }' ``` It is not allowing me to run it, i have mulitple apps running on one server – Red_badger Feb 09 '23 at 12:22
  • The awk command is being executed ahead of the for loop. ++ awk -v resource=ipa '$0~"pcs_"resource { print $2" "$4 }' +++ seq 1 10 ++ ssh -qt chis03 ' '\''for i in 1 2 3 4 5 6 7 8 9 10; do sudo pcs resource disable ipa_; done; sleep 10; sudo pcs status;'\'' ' – Red_badger Feb 09 '23 at 14:24
  • Solution: use single quotes instead of double. this is because i not passing an external variable so dont need to preserve it, just need to use the internal variable to the command. ssh -qt ${site}server${serverA} ' for i in $(seq 1 10); do sudo pcs resource disable ipa_$i; done; sleep 10; sudo pcs status; ' 2>&1 | awk -v resource=ipa '$0~"pcr_"resource { print $2" "$4 }' – Red_badger Feb 09 '23 at 17:14
  • There's nothing wrong with using a here-doc, btw. I just like simple quotes, but if you had needed both single and double quotes in your code, a here-doc is a good way to allow both! It's good to add tools to the toolbox, as long as you understand them and use them effectively. A here-string is another I use a lot, but again, wasn't needed here. – Paul Hodges Feb 09 '23 at 17:39