4

I'm trying to run a set of commands on a remote machine, that includes an if statement. I'm using this to shutdown a list of kvm instances. The first line should be fine, but could be prettier, rest needs some help.

ssh root@kvmsrv 'virsh shutdown $host 2> /dev/null; virsh destroy $host 2> /dev/null; sleep 2; virsh undefine $host 2> /dev/null'

# Also needs to be run on remote machine
# to disconnect iscsi
iscsiadm -m session | grep $host
if [ $? == 0 ]; then
  iscsiadm -m node -T $stserver.$host -u
fi

# then on local machine
tid=`ssh root@storage1 'cat /proc/net/iet/volume' | grep $host | head -1 | awk '{print $1}' | awk -F: '{print $2}'`
if [ $tid ]; then
  echo "Deleting tid:$tid from $stserver."
  ssh root@$stserver "ietadm --op delete --tid=$tid"
fi

I guess I could do the same for the second portion, just separate it all with ; but if anyone goes to read my code later on they'd probably be scratching their heads...

Is there a way to format all this so its readable and still makes sense and have all the remote commands execute properly?

Robert
  • 151
  • 1
  • 6

4 Answers4

4
  1. Put your long and complex sequence of commands in its own shell script, let's call it virsh-shutdown-remote.sh

  2. Run ssh and use input redirection to run the script:

    ssh root@kvmsrv < virsh-shutdown-remote.sh
    

Putting the commands in a script is a good idea in any case.

As an extra tip, instead of this:

iscsiadm -m session | grep $host
if [ $? == 0 ]; then
  iscsiadm -m node -T $stserver.$host -u
fi

You can write the same thing simpler and shorter on a single line:

iscsiadm -m session | grep $host && iscsiadm -m node -T $stserver.$host -u
janos
  • 11,171
  • 3
  • 35
  • 53
3

You can use HEREDOCS, e.g:

ssh root@kvmsrv <<EOF
  virsh shutdown $host 2> /dev/null
  virsh destroy $host 2> /dev/null
  sleep 2
  virsh undefine $host 2> /dev/null

  # to disconnect iscsi
  iscsiadm -m session | grep $host
  if [ \$? == 0 ] ; then
    iscsiadm -m node -T $stserver.$host -u
  fi
EOF

Please be aware that I escaped $? as otherwise it would be evaluated by your local shell and not from your remote shell. As $host seems to be defined locally you won't have to escape it.

Just a small comment though you didn't ask for it. You can remotely run virsh commands, without the need to explicitly ssh into the host, e.g:

virsh -c qemu+ssh://root@kvmsrv/system destroy host

will work. You also don't need ssh as libvirt allows you to authenticate with ssl certs insteads.

Ulrich Dangel
  • 25,079
  • 3
  • 80
  • 80
  • 1
    You forgot to escape his other variables, such as `\$host`, `\$stserver`. In fact it's better to write the whole thing as `ssh root@kvmsrv <<"EOF"` in which case you don't need to escape the `$`-s inside, and just use his script verbatim. – janos Jun 17 '12 at 08:12
  • @janos as i said $host seems to be defined locally - the script never defines/get it somewhere. The same goes for $stserver. But i agree `"EOF"` is often better than escaping. – Ulrich Dangel Jun 17 '12 at 15:55
  • Notice that he single-quoted his very first command, so at least there `$host` is defined on the remote side. In the end he uses `$host` again in a local context, but it would be wrong to assume they are the same. As per his second block of code, from the context I think it's intended to run remotely, using variables defined on the remote, but I agree this is not at all 100% clear. – janos Jun 18 '12 at 04:56
0

Well, the simple answer is that it is actually possible to rewrite ssh root@kvmsrv 'cmd1; cmd2; cmd3' as:

ssh root@kvmsrv '
cmd1
cmd2
cmd3
'

The only thing to remember is that single quotes "inside" single quotes should be expressed as: '\''. Examples:

ssh localhost '
echo hi
whoami
ls -ld /
var="'\''"
echo "$var"
if [ $? == 0 ]; then
   echo "escaping single quote worked"
fi
'

# get single quote from file and print it
echo "'" > sqfile
ssh localhost '
#set -xv
echo hi
cat sqfile
var="$(cat sqfile)"
echo "$var"
'

# pass a single quote to the remote host and print it
# while keeping the outer single quotes for the ssh command
escsquote="'\''"
squote="'"
squote="'${squote//\'/${escsquote}}'" # bash

ssh localhost 'sh -c '\''
#set -xv
echo hi
echo "$1"
'\''' _ "$squote"
marc
  • 11
  • 1
0

Maybe just add commentary to explain things that (should be) obvious? I do this regularly in scripts to remind my own ignorant butt what I was up to when I wrote the [censored] thing in the first place.

killermist
  • 1,591
  • 13
  • 24