Сбор логов с пачки удаленных хостов

Ситуация: есть ряд удаленных виртуалок (на GCE), с которых время от времени надо вытягивать логи. При чем логи надо все и со всех своих машин, поднятых на текущий момент. Вручную это делать не вариант. Надо автоматизировать. Напишем небольшой sh-скрипт, который будет заходить на каждую виртуалку по ssh и вытягивать оттуда /var/log (в tar’e само собой).

#!/bin/bash
 
for host in "$@"
do
	ssh -i gce-key root@"$host" "tar -zcf - /var/log" > node-"$host".tar.gz
done

Скрипт ожидает, что в качестве параметров ему будут переданы ip’ники хостов. В цикле выполняется заход на каждую машину (gce-key — файл с ключом, который должен лежать в папке со скриптом) и выкачивание логов с нее.

Казалось бы, что работа автоматизирована и можно ставить точку. Но хочется добавить больше разных плюшек. Например, я хочу знать, какой по счету хост сейчас обрабатывается:

#!/bin/bash
 
index=1
for host in "$@"
do
	echo "$host [$index of $#]"
	ssh -i gce-key root@"$host" "tar -zcf - /var/log" > node-"$host".tar.gz
	index=$(($index + 1))
done

Отлично. А теперь я хочу, чтоб первый хост был отмечен не как node, а как server:

#!/bin/bash
 
index=1
type="node"
for host in "$@"
do
	echo "$host [$index of $#]"
	if [ $index = 1 ]
		then
			type="server"
		else
			type="node"
	fi
	ssh -i gce-key root@"$host" "tar -zcf - /var/log" > "$type"-"$host".tar.gz
	index=$(($index + 1))
done

А если я забыл, что не положил gce-key в папку со скриптом? Добавим в начале скрипта проверку:

#!/bin/bash
 
GCE="gce-key should be in the current folder!"
 
if [ ! -f gce-key ]
	then 
		echo $GCE
		exit 1
fi
# ....

Для следующей «хотелки» вынесем фрагмент цикла в отдельную функцию:

#!/bin/bash
 
# parameters: 1 - host's index in the array, 2 - host
get_logs () {
	type="node"
	if [ $1 = 1 ] 
		then
			type="server"
	fi
	ssh -i gce-key root@"$2" "tar -zcf - /var/log" > "$type"-"$2".tar.gz
}
 
index=1
for host in "$@"
do
	echo "$host [$index of $#]"
	get_logs $index $host
	index=$(($index + 1))
done

Перечислять хосты в качестве аргументов скрипта хорошо до определенного момента — пока их (хостов) не очень много. Когда виртуалок уже больше 5, то хочется сложить ip’шники в отдельный файлик и «скормить» его скрипту. В реализации этой идеи возникает вопрос — как понять, что нам передали файл, а не ip.

#!/bin/bash
 
 
if [ -f "$1" ]; 
	then
		# first argument is a file
	else
		# first argument is not a file
fi

Рассмотрим возможную структуру файла:

hostName1	ip1
hostName2	ip2
...
hostNameN	ipN
ip1
ip2
...
ipN

Каждая запись о хосте на отдельной строке и может содержать имя хоста перед ip-адресом. Пробелов/табуляций может быть сколько угодно.

Со структурой понятно. Теперь надо написать пару строк, чтоб правильно распарсить такой файл:

#!/bin/bash
 
hosts=$(cat "$1" | sed 's/[^ ]* //g;s/\n/ /g;')
tmp=( $hosts )
count=${#tmp[@]}

Основную работу тут выполнена на третьей строке — прочитали содержимое файла, передали его в sed и там уже убрали все «лишнее». tmp нужно только для того, чтоб получить кол-во полученных ip (потому что hosts являет собой строку, а не массив).

Теперь скрипт выглядит как-то так:

#!/bin/bash
 
 
# parameters: 1 - host's index in the array, 2 - host
get_logs () {
	type="node"
	if [ $1 = 1 ] 
		then
			type="server"
	fi
	ssh -i gce-key root@"$2" "tar -zcf - /var/log" > "$type"-"$2".tar.gz
}
 
index=1
if [ -f "$1" ]; 
	# file_with_hosts is provided
	then
		hosts=$(cat "$1" | sed 's/[^ ]* //g;s/\n/ /g;')
		tmp=( $hosts )
		count=${#tmp[@]}
		for host in $hosts
		do
			echo "$host [$index of $count]"
			get_logs $index $host
			index=$(($index + 1))
		done
	else
		# list of hosts is provided as agruments
		for host in "$@"
		do
			echo "$host [$index of $#]"
			get_logs $index $host
			index=$(($index + 1))
		done
fi
echo "Done!"

Добавим небольшое описание про использование скрипта и проверку параметров:

#!/bin/bash
 
me=$(basename $0)
 
GCE="gce-key should be in the current folder!"
USAGE="Usage:\t$me ip1 ip2 .. ipN\n\n\t$me file_with_hosts.txt\n\n\t\tfile_with_hosts:\n\t\t\thostname1 ip1\n\t\t\thostname2 ip2\n\t\t\t...\n\t\t\thostnameN ipN\n\n\t\tfile_with_hosts:\n\t\t\tip1\n\t\t\tip2\n\t\t\t...\n\t\t\tipN\n\n\tnotice: $GCE";
 
# no parameters are provided
if [ -z "$1" ]
	then
		echo -e $USAGE
		exit 1
fi

Конечная версия получается такая:

#!/bin/bash
 
me=$(basename $0)
 
GCE="gce-key should be in the current folder!"
USAGE="Usage:\t$me ip1 ip2 .. ipN\n\n\t$me file_with_hosts.txt\n\n\t\tfile_with_hosts:\n\t\t\thostname1 ip1\n\t\t\thostname2 ip2\n\t\t\t...\n\t\t\thostnameN ipN\n\n\t\tfile_with_hosts:\n\t\t\tip1\n\t\t\tip2\n\t\t\t...\n\t\t\tipN\n\n\tnotice: $GCE";
 
# no parameters are provided
if [ -z "$1" ]
	then
		echo -e $USAGE
		exit 1
fi
 
if [ ! -f gce-key ]
	then 
		echo -e $GCE
		exit 1
fi
 
# parameters: 1 - host's index in the array, 2 - host
get_logs () {
	type="node"
	if [ $1 = 1 ] 
		then
			type="server"
	fi
	ssh -i gce-key root@"$2" "tar -zcf - /var/log" > "$type"-"$2".tar.gz
}
 
index=1
if [ -f "$1" ]; 
	# file_with_hosts is provided
	then
		hosts=$(cat "$1" | sed 's/[^ ]* //g;s/\n/ /g;')
		tmp=( $hosts )
		count=${#tmp[@]}
		for host in $hosts
		do
			echo "$host [$index of $count]"
			get_logs $index $host
			index=$(($index + 1))
		done
	else
		# list of hosts is provided as agruments
		for host in "$@"
		do
			echo "$host [$index of $#]"
			get_logs $index $host
			index=$(($index + 1))
		done
fi
echo "Done!"

При изменении под свои нужды необходимо в функции get_logs поменять синтаксис команды ssh. В остальном — скрипт в меру универсален.

, ,

Оставить комментарий

Top ↑ | Main page | Back