Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Крупный провайдер. Сегментированная сеть с кучей цисок. И одна циска центральная.
Обычный день, ничто не предвещает беды. Вдруг падает вся сеть. Народ в панике ищет в чём проблема. Оборачивается один сисадмин и говорит: «Я дико извиняюсь. Программировал новую циску. Стёр конфиг старый, перегрузил… Оказалось, это был центральный маршрутизатор… Окошком ошибся»
main([Cmd | Hosts]) ->
Timeout = 5000,
Master = self(),
erlang:send_after(Timeout, self(), timeout), % запускаем таймер
%% используем генератор списков для запуска параллельной задачи на каждый хост
[spawn_link(fun() -> task(Host, Cmd, Master, Timeout) end) || Host <- Hosts],
await(length(Hosts)).
task(Host, Cmd, Master, Timeout) ->
%% использует $USER, $HOME/.ssh/id_rsa по умолчанию
{ok, Conn} = ssh:connect(Host, 22, {}, Timeout), %тут timeout чисто номинально
%% SSH поддерживает мультиплексирование
{ok, Chan} = ssh_connection:session_channel(Conn, Timeout),
success = ssh_connection:exec(Conn, Chan, Cmd, Timeout),
Response = read_response(Conn, Chan, <<>>),
%% отправляем результат выполнения мастеру
Master ! {result, Host, Response}.
await(0) -> ok; % все результаты получены. Выходим.
await(N) ->
receive
{result, Host, Response} -> % пришло сообщение от одной из задач
io:format("Host: ~s; Response: ~p~n", [Host, Response]),
await(N - 1); % зацикливаемся
timeout -> % пришло сообщение от таймера
io:format("Timeout, but ~p tasks not ready!", [N])
end.
read_response(Conn, Chan, Acc) ->
%% рекурсивно читаем ответ команды
receive
{ssh_cm, Conn, {data, Chan, _, Data}} ->
%% цикл, собираем результат выполнения команды в аккумулятор
read_response(Conn, Chan, <<Acc/binary, Data/binary>>);
{ssh_cm, Conn, {closed, Chan}} ->
%% Команда отработала. Разрываем рекурсию.
Acc
end.
conn.NewSession() на каждую команду вроде ничего сложного. Но это не так часто нужно. Обычно нужно подключиться и выполнить одну-две команды.
Исполнение SSH-команд на сотнях серверов с помощью Go