"скрипто-писание" н...
 

"скрипто-писание" начинающим, правила хорошего тона, на примере мониторинга UPS и дисков

7 Записи
3 Пользователи
0 Reactions
1,681 Просмотры
(@shkiper)
Active Member
Присоединился: 5 лет назад
Записи: 16
Создатель темы  

у меня небольшой опыт в линуксе и я не разработчик ПО, но есть опыт работы с разработчиками которые очень строго стараются следовать общепринятым традициям написания кода, т.н. "правилам хорошего тона" 

хочу поделится методом (приемами) написания скриптов на bash для получения ключей zabbix клиента, заодно в качестве примера приведу реальный скрипт для получения параметров мониторинга UPS

абсолютно ничего особенного в этом нет, это все давно всем известно, но начинающим будет полезно

итак, есть у нас например несколько ключей, которые выглядят примерно так

UserParameter=uHDD.temp[*],sudo /etc/zabbix/disksmart.sh $1 | grep "194 Temp"| sed 's/\s\+/,/g' | cut -f10 -d,
UserParameter=uHDD.bb[*],sudo /etc/zabbix/disksmart.sh $1 | grep "5 Re"| sed 's/\s\+/,/g' | cut -f11 -d,
UserParameter=uHDD.ph[*],sudo /etc/zabbix/disksmart.sh $1 | grep "9 Pow"| sed 's/\s\+/,/g' | cut -f11 -d,
UserParameter=uHDD.wlc[*],sudo /etc/zabbix/disksmart.sh $1 | grep "177 We"| sed 's/\s\+/,/g' | cut -f10 -d,
UserParameter=uHDD.tlw[*],sudo /etc/zabbix/disksmart.sh $1 | grep "241 Tot"| sed 's/\s\+/,/g' | cut -f10 -d,
UserParameter=uHDD.ps[*],sudo /etc/zabbix/disksmart.sh $1 | grep "197 Curr"| sed 's/\s\+/,/g' | cut -f10 -d,

в принципе нормально, главное - все рабтает :)

не совсем красиво, для каждого ключа нужна своя строка

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

UserParameter=ups.status[*],sudo /etc/zabbix/upsmon.sh $1

это на примере UPS, так выглядит универсальная строка для всех запрашиваемых параметров UPS

в случае с дисками можно например привести все к виду:

UserParameter=smarthdd[*],sudo /etc/zabbix/disksmart_new.sh $1 $2

где первый параметр - диск, второй - запрашиваемый параметр диска

но вернемся к UPS, мониторинг настроен с помощью NUT

UPS ippon с NUT и Zabbix

я написал немного другой скрипт, кроме параметров  UPS добавил туда еще контроль наличия подключения по usb и наличие запущенного демона

ну и конечно, т.к. параметров у нас достаточно, а периоды опроса не очень большие (питание дело серьезное) чтоб для получения каждого ключа не запускать исполняемый фай, применим прием с кэшем (кто-то может сказать, что я этот прием применяю где надо и где не надо, и возможно будет прав)

#!/bin/bash
 
HOST="localhost"
PORT="80"
stub_status=server-status
 
function check_daemon() {
         ps ax | grep -c "[b]lazer_usb"
}
 
function check_conn() {
         tail -n1 /var/log/syslog | grep ups | grep -c "unavailable\|stale"
}
 
CACHE_TTL="55"
CACHE_FILE="/tmp/zabbix.ups.cache"
 
EXEC_TIMEOUT="2"
NOW_TIME=`date '+%s'`
 
if [ -s "${CACHE_FILE}" ]; then
  CACHE_TIME=`stat -c"%Y" "${CACHE_FILE}"`
else
  CACHE_TIME=0
fi
DELTA_TIME=$((${NOW_TIME} - ${CACHE_TIME}))
 
if [ ${DELTA_TIME} -lt ${EXEC_TIMEOUT} ]; then
  sleep $((${EXEC_TIMEOUT} - ${DELTA_TIME}))
elif [ ${DELTA_TIME} -gt ${CACHE_TTL} ]; then
  DATACACHE=`upsc myups 2>&1 | grep -v '^Init SSL'`
        echo "" >> "${CACHE_FILE}" # !!!
        echo "${DATACACHE}" > "${CACHE_FILE}" # !!!
        chmod 640 "${CACHE_FILE}"
 
fi
 
function charge() {
        cat "${CACHE_FILE}" 2>/dev/null| grep 'charge:' | awk '{print $NF}'
}
 
function status() {
        cat "${CACHE_FILE}" 2>/dev/null| grep 'ups.status:' | awk '{print $2}'
}
 
function input_v() {
        cat "${CACHE_FILE}" 2>/dev/null| grep 'input.voltage:' | awk '{print $2}'
}
 
function output_v() {
        cat "${CACHE_FILE}" 2>/dev/null| grep 'output.voltage:' | awk '{print $2}'
}
 
 
function load() {
        cat "${CACHE_FILE}" 2>/dev/null| grep 'load:' | awk '{print $2}'
}
 
function bat_v() {
        cat "${CACHE_FILE}" 2>/dev/null| grep 'battery.voltage:' | awk '{print $2}'
}
 
function temp() {
cat "${CACHE_FILE}" 2>/dev/null| grep 'temperature:' | awk '{print $2}'
}
 
case "$1" in
        check_daemon)
                check_daemon
                ;;
        check_conn)
                check_conn
                ;;
        charge)
                charge
                ;;
        status)
                status
                ;;
        input_v)
                input_v
                ;;
        output_v)
                output_v
                ;;
        load)
                load
                ;;
        bat_v)
                bat_v
                ;;
        temp)
                temp
                ;;
 
 
        *)
                echo $"Usage $0 {check_daemon|check_conn|charge|status|input_v|output_v|load|bat_v|temp}"
                exit
esac

 


   
ОтветитьЦитата
(@shkiper)
Active Member
Присоединился: 5 лет назад
Записи: 16
Создатель темы  
От: @shkiper

*) echo $"Usage $0 {check_daemon|check_conn|charge|status|input_v|output_v|load|bat_v|temp}"

обратите внимание на эту строку, если будет передана в качестве параметра строка с неизвестным скрипту параметром, он выдаст пояснение о том что он ожидает увидеть, обработка исключений важный момент в работе кода

От: @shkiper

ps ax | grep -c "[b]lazer_usb"

квадратные скобки на первой букве позволяют исключить из списка найденных процессов сам процесс поиска

От: @shkiper

tail -n1 /var/log/syslog | grep ups | grep -c "unavailable\|stale"

ключ "-с" в grep выводит количество найденных строк, появился не так давно, рекомендуют использовать  вместо "wc -l"

Это сообщение было изменено 5 лет назад от Shkiper

   
ОтветитьЦитата
(@shkiper)
Active Member
Присоединился: 5 лет назад
Записи: 16
Создатель темы  

не так давно переписал скрипт для мониторинга дисков, теперь все параметры всех дисков прописаны одной строкой:

UserParameter=smarthdd[*],sudo /etc/zabbix/disksmart_new.sh $1 $2

ну и сам скрипт, по коду думаю все понятно - какие параметры беруться, и таки да кроме параметров состояния, беру серийник, модель, наработку

потому что удобно все видеть сразу в одном месте, когда возникают вопросы, а кэширование позволяет не беспокоится об излишней нагрузке, да и периоды опроса этих ключей большие

#!/bin/bash
 
if [ -z "$1" ]; then
  echo $"Usage $0 sda|sdb|sdx"
  exit 1
fi
 
if [ -z "$2" ]; then
  echo $"Usage $0 $1 {temp|ph|wlc|tbw|ps|bb|model|sn|health}"
  exit 1
fi
##### PARAMETERS #####
nHDD="$1"
SMART_PARAM="$2"
 
CACHE_TTL="55"
CACHE_FILE="/tmp/smartctl.`echo ${nHDD} | md5sum | cut -d" " -f1`.cache"
EXEC_TIMEOUT="5"
NOW_TIME=`date '+%s'`
##### RUN #####
 
if [ -s "${CACHE_FILE}" ]; then
  DATACACHE=$(cat "${CACHE_FILE}")
  LAST_FILE=`find /tmp/smartctl* -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r | head -n1 | sed 's/\s\+/,/g' | cut -f3 -d,`
  CACHE_TIME=`stat -c"%Y" "${LAST_FILE}"`
else
  CACHE_TIME=0
fi
DELTA_TIME=$((${NOW_TIME} - ${CACHE_TIME}))
if [ ${DELTA_TIME} -lt ${EXEC_TIMEOUT} ]; then
  sleep $((${EXEC_TIMEOUT} - ${DELTA_TIME}))
elif [ ${DELTA_TIME} -gt ${CACHE_TTL} ]; then
  DATACACHE=`smartctl -a /dev/"${nHDD}" 2>&1`
        echo "" >> "${CACHE_FILE}" # !!!
        echo "${DATACACHE}" > "${CACHE_FILE}" # !!!
        chmod 640 "${CACHE_FILE}"
fi
 
function temp () {
        cat "${CACHE_FILE}" 2>/dev/nul | grep "194 Temp"| sed 's/\s\+/,/g' | cut -f10 -d,
}
 
function ph () {
        cat "${CACHE_FILE}" 2>/dev/null| grep "9 Pow"| sed 's/\s\+/,/g' | cut -f11 -d,
}
 
function wlc () {
        cat "${CACHE_FILE}" 2>/dev/null| grep "177 We"| sed 's/\s\+/,/g' | cut -f10 -d,
}
 
function tbw () {
        cat "${CACHE_FILE}" 2>/dev/null| grep "241 Tot"| sed 's/\s\+/,/g' | cut -f10 -d,
}
 
function ps () {
        cat "${CACHE_FILE}" 2>/dev/null| grep "197 Curr"| sed 's/\s\+/,/g' | cut -f10 -d,
}
 
function bb () {
        cat "${CACHE_FILE}" 2>/dev/null| grep "5 Real"| sed 's/\s\+/,/g' | cut -f11 -d,
}
 
function model () {
        cat "${CACHE_FILE}" 2>/dev/null| grep "Device Model"| sed 's/\s\+/,/g' | cut -f3-4 -d,
}
 
function sn () {
        cat "${CACHE_FILE}" 2>/dev/null| grep "Serial Number"| sed 's/\s\+/,/g' | cut -f3 -d,
}
 
function health () {
        smartctl -H /dev/${nHDD} |grep "test"| cut -f2 -d: |tr -d " "
}
 
 
case ${SMART_PARAM} in
        temp)
                temp
                ;;
        ph)
                ph
                ;;
        wlc)
                wlc
                ;;
        tbw)
                tbw
                ;;
        ps)
                ps
                ;;
        bb)
                bb
                ;;
        model)
                model
                ;;
        sn)
                sn
                ;;
        health)
                health
                ;;
 
        *)
                echo $"Usage $0 ${nHDD} {temp|ph|wlc|tbw|ps|bb|model|sn|health}"
                exit
esac
 
exit 0

   
ОтветитьЦитата
(@shkiper)
Active Member
Присоединился: 5 лет назад
Записи: 16
Создатель темы  

так же думаю переписать скрипт обнаружения для LLD на lsblk

в свежих линуксах для команды lsblk появился ключ -J 

-J, --json use JSON output format

получается практически готовый шаблон для LLD

и значительно выросло количество доступных столбцов для параметра "-o", в т.ч. выдает и модель, и серийный номер (его раньше не было), т.е. можно обойтись без использования smartctl (не во всех случаях конечно) и поулучить параметры, которых в smartctl нет, точку монтирования устройства например, иногда очень надо увидеть в параметрах устройства куда оно смонтировано

т.е. в задумках переписать LLD и более его привязать к параметрам состояния тома, а не только устройства

хотя наверно в 4.2 какие-то новшества есть на этот счет


   
ОтветитьЦитата
(@zerox)
Prominent Member Admin
Присоединился: 11 лет назад
Записи: 926
 

@shkiper

Интересная информация про lsblk и json формат. Это очень удобно, не знал об этом.


   
ОтветитьЦитата
(@shkiper)
Active Member
Присоединился: 5 лет назад
Записи: 16
Создатель темы  
От: @shkiper

grep -c "unavailable\|stale"

в данной строке стоит обратить внимание на фильтр - "unavailable\|stale"

т.е. используется "логическое или", в список выборки попадут строки включающие "unavailable" или "stale", но что бы символ "|" воспринимался как оператор сравнения, а не просто символ, перед ним надо поставить знак "\"


   
ОтветитьЦитата
STALKER_SLX
(@stalker_slx)
Reputable Member
Присоединился: 6 лет назад
Записи: 202
 

@shkiper

Спасибо Вам за оригинальные методы! Сам в скриптах не очень силён, поэтому для меня это будет полезным :)

Это сообщение было изменено 5 лет назад от STALKER_SLX

   
ОтветитьЦитата
Используешь Telegram? Подпишись на канал автора →
This is default text for notification bar