Я обновляю около 20 сценариев bash, которые выполняют различные операционные задачи на стороне сервера, проверяют статус / отправляют отчеты и т. Д. В некоторых средах эти сценарии будут запускаться локально, в других им необходимо запускать удаленно. Скрипты должны определять, нужно ли им запускать удаленно или локально, и «делать правильные вещи».
#!/bin/bash
# Generate the foo report
execute_host=appdev7
if [[ "$execute_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
ssh "$execute_host" < $0
else
# run report
echo "Report"
fi
Некоторые скрипты используют общие функции и переменные среды. Я могу передавать переменные среды с помощью опции ssh SendEnv, но я не могу найти хороший способ сделать общие функции доступными при удаленном запуске.
./shared.sh
# Shared functions and variables
export report_host="appdev7"
function run_report() {
# run report
echo 'Report'
}
./пример
#!/bin/bash
# Generate the foo report
[[ -f shared ]] && source ./shared.sh
export execute_host="$report_host"
if [[ "$execute_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
ssh -o SendEnv='report_host' "$execute_host" < $0
else
# This doesn't work when the script is run remotely
run_report
fi
shared.sh
на всех наших хостах, но мне нужно как-то синхронизировать файлы, и в какой-то момент это неизбежно пойдет не так.shared.sh
на общем ресурсе NFS, но если NFS выйдет из строя, мы потеряем возможность использовать наши скриптыshared.sh
на сервер перед запуском скрипта. Это сработает, но может быть немного медленным, и если shared.sh
зависит от какого-то другого скрипта, нам также придется скопировать этот файлdeclare -f
чтобы извлечь код моих функций, но я не могу придумать хороший способ перетасовать их на удаленный сервер. Зависимости функций также могут вызывать проблемы.Самое чистое решение, которое я могу найти, - это запустить встроенную общую библиотеку с помощью Замена процесса:
#!/bin/bash
# Generate the foo report
# source the shared code/vars if we're running locally
[[ -f shared.sh ]] && source shared.sh
execute_host="$report_host"
if [[ "$execute_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
# Note that we source the shared library in-line with the script
ssh -T "$execute_host" < <(cat shared.sh $0)
else
run_report
fi
Тогда мои вопросы:
shared.sh
? (например, если shared.sh
зависит от shared2.sh
)Так что для решения этой задачи я использовал другой подход. Сначала я создал исполняемый скрипт под названием remotely
1:
#!/bin/bash
# Usage:
# Put this thing as a shebang into your scripts
# i.e.:
#
# #!/bin/remotely user@your-server.com
#
# echo "hello world from ${hostname}"
#
login=$1
script=$2
args=${@#$1}
args=${args#$2}
tar cz $script | ssh $login "tar xz && bash --login $script $args"
А потом использовать его в моих скриптах, которые должны выполняться удаленно:
#!/bin/remotely user@your-server.com
echo "hello world from ${hostname}"
Его также можно настроить для поддержки нескольких хостов, используя что-то вроде gnu-parallel
.
Отвечая на свой вопрос здесь.
Теперь у нас есть такая функция:
function remote::run() {
# usage: remote::run "host" "includes" "commands"
# where "includes" is a list of functions to export to
# the remote host
[[ -n "$2" ]] && includes="$(declare -f $2);"
ssh -T $1 "$includes $3"
}
Это позволяет нам делать такие вещи (надуманный пример):
function status::report() {
date
host $(hostname)
}
remote::run $REMOTE_HOSTNAME status::report 'echo status report:; status::report' > out
Это далеко не идеально, но менее уродливо, чем было у нас :)
Предыдущий ответ:
Было сложно проследить за потоком управления в приведенных выше сценариях, я думаю, что остановился на чем-то вроде этого:
#!/bin/bash
# Generate the foo report
# source the shared code/vars if we're running locally
[[ -f shared.sh ]] && source shared.sh
if [[ "$report_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
runner="ssh -T -o SendEnv=report_host $report_host"
else
# run report locally
runner="bash"
fi
report="$($runner << EOF
$(declare -f run_report)
run_report
EOF
)"
echo "$report" | mail -s "daily foo report" root
Я не в восторге от того, что удаленный код находится в heredoc. Пока остается несколько объявлений, за которыми следует простой вызов функции, я думаю, что это нормально.