Я бы хотел использовать ssh
с ControlMaster функция обмена соединениями для увеличения скорости. Я пытаюсь написать сценарий, чтобы я мог запускать / перезапускать / останавливать несколько подключений к разным хостам.
Как я могу определить, используются ли какие-либо из этих подключений? Если я убью их, когда сеанс ssh открыт, он закроется
Мой сценарий перезапуска в идеале выглядел бы как (псевдосценарий) - сценарий остановки был бы эквивалентен без команды ssh внизу:
for HOST in $HOST_LIST
do
MASTER_PID=`find_master_pid $HOST`
if $MASTER_PID
then
if `find_child_pid`
echo Connection to $HOST in use: not terminating
else
kill -SIGHUP $MASTER_PID
fi
ssh -TMNf $HOST
Вы можете просто использовать
ssh -o ControlPath=$socket -O check
для каждого открытого вами сокета $ (легко, если вы храните их в одном каталоге).
Это возвращает 255, если проверка не удалась (соединение больше не активно), другое значение, если оно прошло. Возможно, вам также потребуется указать имя хоста, но ничего, что вам не даст awk на $ socket :)
@ Ответ Реника не сработал для меня. См. Ниже, что было сделано.
Это работает для меня, используя только файл сокета для мастера управления:
$ ssh -o ControlPath=~/.ssh/<controlfile> -O check <bogus arg>
НОТА: Вы также можете использовать ssh -S ~/.ssh/<controlfile> ...
а также, что является немного более короткой формой вышеупомянутого.
Вот пример, когда я уже установил соединение с удаленным сервером:
$ ssh -S ~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check blah
Master running (pid=89228)
$
И при отключенном:
$ ssh -S ~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O check blah
Control socket connect(/Users/user1/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74): No such file or directory
$
Если бы он все еще был подключен, это заставило бы его немедленно выйти:
$ ssh -S ~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O exit blah
Exit request sent.
$
Мне непонятно, но может показаться, что это ошибка в ssh
что в конце требуется дополнительный аргумент, хотя blah
не имеет смысла в контексте используемых мной переключателей.
Без него я получаю следующее:
$ ssh -S ~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check
usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
[-D [bind_address:]port] [-E log_file] [-e escape_char]
[-F configfile] [-I pkcs11] [-i identity_file]
[-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]
[-O ctl_cmd] [-o option] [-p port]
[-Q cipher | cipher-auth | mac | kex | key]
[-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]
[-w local_tun[:remote_tun]] [user@]hostname [command]
$ ssh -V
OpenSSH_6.9p1, LibreSSL 2.1.8
CentOS 7.x $ ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017
Я подтвердил, что в обеих этих версиях требовался дополнительный ложный аргумент.
Я написал утилиту, которая упрощает управление SSH-соединениями ControlMaster. Это называется cmc
: TimidRobot / cmc: ControlMaster Controller - упрощает управление SSH-соединениями ControlMaster.
Мой нынешний подход - использовать lsof
чтобы найти сокеты Unix. Если я знаю целевое имя файла, указанное ControlPath
Я могу искать основной процесс так:
function find_master_pid() {
lsof -a -U -u $USER -c ssh | grep $CM_DIR/$RUSER@$HOST | sed 's/^ssh *//' | cut -d' ' -f1 | sort -u
}
Это даст мне PID
(к сожалению, указание имени файла сокета unix непосредственно в lsof
не работает, иначе я мог бы просто попросить его вывести мне pid
с участием -f
; следовательно sed
и cut
)
Найти дочерний процесс сложнее. Главный процесс открывает новый сокет для каждого дочернего процесса, подключенного к стандартному файлу. Дочерний процесс содержит сокет, просто помеченный socket
. Однако индексный дескриптор, возвращаемый lsof
на единицу меньше, чем соответствующий сокет главного процесса. Таким образом, следующее обнаруживает дочерние процессы, которые подключены к главному процессу (для этого требуется $MASTER_PID
проверить против)
function find_child_pid() {
for CHILD_PID in `lsof -a -U -u $USER -c ssh | grep socket | sed 's/^ssh *//' | cut -d' ' -f1 | sort -u`
do
CHECK_PID=0
for NODE in `lsof -a -U -u $USER -p $CHILD_PID -F i | grep ^i | sed 's/i//'`
do
MASTER_NODE=$((NODE+1))
CHECK_PID=`lsof -a -U -u $USER -p $MASTER_PID | grep $MASTER_NODE | wc -l`
[[ $CHECK_PID == 1 ]] && echo $CHILD_PID
done
done
}