22

Possible Duplicate:
Using an already established SSH channel

Here is my sync script:

ssh user@remote.host /etc/init.d/some_service stop
scp user@remote.host:/var/some_service/events ./events
scp ./new_data user@remote.host:/var/some_service/new_data
ssh user@remote.host /etc/init.d/some_service start

As You can see, it stops service, perform some copies with scp and starts service back.

The problem: it "costs" 4 "similar" ssh connections in a row.

Is there any way to make all the work, using one physical ssh connection?

Arenim
  • 341

3 Answers3

25

You could consider to use ssh connection sharing:

Host *.some-domain
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p

You connect only once to your destination, and put the ssh process in background. Then you execute the other commands and you finally kill the first process.

In alternative you can try to encapsulate a bunch of actions within one single ssh connection.

For example, imagine that you have a directory:

 mycommands
 |
 +- run
 +- new_data

Then you can pack this data in a tar and send it to your script:

tar cf - -C mycommands . | ssh localhost 'D=`mktemp -d`; tar xf - -C $D; $D/run'

Now you run script can access to all your input data (here we have only the new_data as in your example). To stick with your example, here's the run script:

#!/bin/sh
BASE=`dirname $0`

/etc/init.d/some_service stop
cat /var/some_service/events

mv $BASE/new_data /var/some_service/new_data
/etc/init.d/some_service start

rm -rf $BASE

So, now you just have to save the events file:

tar cf - -C mycommands . | ssh localhost 'D=`mktemp -d`; tar xf - -C $D; $D/run' >./events

and more generally you can have your run script produce a tar and then pipe ssh into tar to unpack it locally.

mkm
  • 351
4

You could move this logic to a script that runs on the destination server, then execute it with a single SSH command. Presumably this is not ideal though, otherwise you would have done so already :)

You can mitigate the cost of opening a new SSH connection by using an SSH master connection. This means that your first SSH command will open a new connection, as normal. Subsequent connections to the same server will reuse this existing connection, thus saving you the overhead of creating three additional connections.

There's a good guide to setting this up here: http://www.linuxjournal.com/content/speed-multiple-ssh-connections-same-server

  • to your first paragraph. why is this not ideal? this seems like a completely fine way of going about it. in fact i do this often. –  Dec 06 '12 at 12:23
  • Primarily for security reasons. In his example, he is running some commands on serverA, which push some files to serverB. He might not want serverB to be able to pull files from serverA. In the past I have set up backup systems where the backup host could connect to all production servers to pull files. If the production servers have permissions to log in to the backup server, that could be a security risk (someone hacks your prod server and then deletes your backups). –  Dec 06 '12 at 12:41
  • 3
    One addition... You can accomplish this without actually copying the script to the remote server... Say you have a script named sync.sh on your main server. Let's say it contains the commands to stop and start your service, as well as a call to scp the files you need. You can execute this script on the remote server without copying it to the remote server by using: ssh user@remote.host < sync.sh This is handy if you don't want to have to manage the script on multiple remote systems. I use this for [hardware/inventory collection](http://serverfault.com/questions/365238/documenting-server-de – ewwhite Dec 06 '12 at 13:22
1

this assumes that, the local server trusts the remote server to run command w/o password, otherwise it will not work as you are running a so-called headless connection, with no way to provide input

ssh remoteserver "/etc/init.d/some_service stop; scp /var/some_service/events localhost:${PWD}/events; scp localserver:${PWD}/new_data /var/some_service/new_data; /etc/init.d/some_service start"

all off the above code needs to be on one contiguous line on your terminal, or if you are running it from inside a script, this should all be one command, not separated by line feeds.

if you have a trusted key-pair from the remote server to the local server, I don't see any reason why this shouldn't work.

MelBurslan
  • 6,966