UMGUM.COM (лучше) 

Автоматизация AoE-импорта ( Контроль за импортом блочных устройств файловой системы. )

1 августа 2010  (обновлено 28 октября 2018)

OS: Linux Debian Lenny/Squeeze.

Будем исходить из того, что наша распределённая файловая система на разнесённых по сети блочных устройствах сосредоточена в одном широковещательном сегменте и все обнаруженные AoE блоки подлежат импорту в локальную файловую систему сервера, сводящего блоки AoE в единое целое. В общем, всё, что обнаружим - будем пробовать подмонтировать.

В реализации модуля AoE для Debian Lenny/Squeeze есть парочка нюансов, которая оказала существенное влияние на методы контроля за нашей распределённой файловой системой. Во первых, автоматически не очищаются списки обнаруженных AoE устройств по таймауту, даже тогда, когда таковые явно не отвечают уже несколько часов. Во вторых, даже после того, как отсутствие связи с AoE-устройством обнаружено с помощью соответствующих утилит, оно отключено физически, прекращён экспорт и импорт этого устройства, на стороне сервера-сборщика ссылка на устройство освобождена от использования кем бы-то ни-было, устранены все причины, по которым это устройство могло бы понадобится, даже указание принудительного его удаления с помощью утилиты aoe-flush не гарантирует исчезновение этого устройства из списка доступных. Единственный способ гарантировано почистить изменившийся список, после модификации физических носителей информации, например - это размонтирование файловой системы, освобождение ссылок на AoE-устройства, выгрузка модуля AoE, загрузка его заново, поиск AoE устройств и сборка файловой системы заново.


# mkdir -p /var/log/aoe-import

Создаём подключаемый конфигурационный файл, в котором будут определены некоторые общие параметры, вроде: списка отрабатываемых устройств, из количества и тому подобного:

# vi /etc/default/aoe-import.conf

OBJECTS=""

# Количество импортируемых файловых систем
NUMBERFS="20"

# Перечень адресов электронных почтовых ящиков, на которые высылаются уведомления
EMAIL="mail@example.net"

Создаём непосредственно скрипт запуска импорта, включающий в себя функционал проверки состояния импортированных файловых систем и запуска соответстсвующих операций устранения последствий неисправностей:

# vi /etc/init.d/aoe-import && chmod ugo+x /etc/init.d/aoe-import

#! /bin/bash

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin

### BEGIN INIT INFO
# Provides:          aoe-import
# Required-Start:    $local_fs $network
# Required-Stop:     $local_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: start scripts import and assembly FS
# Description:       start the import of remote FS and assembly them locally
### END INIT INFO

# Подключим файл с настройками
if [ -f /etc/custom/hdd/aoe-import.conf ]
then
  . /etc/custom/hdd/aoe-import.conf
fi

HOSTNAME=`cat /etc/hostname`
# INTERFACE="eth0"
INTERFACE="bond0"
DATE=`date +"%Y-%m-%d %H:%M:%S"`
LOG=/var/log/aoe-import/aoe-import.log

# Определяем функцию уведомления администратора о нештатном развитии ситуации
function send-report() {
  local LOCAL_OBJECT=$1
  local LOCAL_REPORT=$2
  # Посылаем электронное письмо с уведомлением о проблеме
  echo -e "Content-Type: text/plain; charset="utf-8"\nSubject: Warning AoE-import: ${HOSTNAME}: /dev/${LOCAL_OBJECT}\n${DATE}.\nHost: ${HOSTNAME}.\nDevice: /dev/${LOCAL_OBJECT}.\n${LOCAL_REPORT}" | sendmail -F${HOSTNAME} ${EMAIL}
return 0
}

# Определяем функцию проверки состояния корневой точки монтирования (MHDDFS) (к сожалению, по неясным причинам, иногда драйвер MHDDFS перестаёт отображать свою файловую систему в точку монтирования)
function check-mhddfs() {
#  TEST=`df -h | grep -i "/mnt/storage" | grep -i "not connected"`
  TEST=`df 2>&1 | grep -i "/mnt/storage" | grep -i "not connected"`
  if [ "${TEST}" != "" ]
  then
    send-report "MHDDFS" "Warning! MHDDFS не отображает FS в точку монтирования."
    echo >&2 "Warning! MHDDFS не отображает FS в точку монтирования."
    return 1
  fi
return 0
}

# Определяем функцию последовательных тестов доступности импортируемых блочных устройств
function check-import() {
  # Проверяем факт запуска AoE по созданным им конструкциям
  if [ ! -e /dev/etherd/discover ]
  then
    # Загружаем модуль AoE, если этого не было сделано ранее
    echo "Waiting 3 seconds for correct load and configure module AoE..."
    modprobe aoe
    aoe-interfaces ${INTERFACE}
    aoe-discover
    sleep 3
    if [ ! -e /dev/etherd/discover ]
    then
      send-report "AoE" "Warning! AoE не работает или работает некорректно."
      echo >&2 "Warning! AoE не работает или работает некорректно."
      return 1
    fi
  fi

  # Закручиваем цикл в ожидании обнаружения всех импортируемых блочных устройств
  COUNT="0"
  aoe-discover
  until [ "`ls -l /dev/etherd/ | grep -c '^brw'`" = "${NUMBERFS}" ]
  do
    sleep 1
    let COUNT=${COUNT}+1
    echo "Wait for discover all AoE devices... ${COUNT} sec."
    if [ "${COUNT}" -gt "600" ]
    then
      # Паникуем, что за десять минут не обнаружены все ожидаемые блочные устройства
      send-report "AoE-import" "Panic! Не все блочные устройства были импортированы в течении десяти минут."
      echo >&2 "Не все блочные устройства были импортированы в течении десяти минут."
      return 1
    fi
    aoe-discover
  done

  # Переходим в директорию, где располагаются импортируемые блочные устройства
  cd /dev/etherd/

  # Тестируем все импортируемые блочные устройства на предмет доступности
  for OBJECT in *
  do
    # Проверяем, является ли файл блочным устройством
    if [ -b "./${OBJECT}" ]
    then

      # Получаем в переменные назначенный устройству индекс
      INDEXT=`echo "${OBJECT}" | cut -c 2-`
      INDEXF=`echo ${INDEXT} | awk -F . '{print $1}'`
      INDEXS=`echo ${INDEXT} | awk -F . '{print $2}'`

      echo "${DATE}: e${INDEXF}.${INDEXS}" >> ${LOG}

      # Проводим многократный тест, оценивая доступность устройства по суммарным показателям (на случай, если ответ от удалённого устройства задержался в связи с сильной загруженностью сетевой инфраструктуры, что бывает)
      RETCOUNT="0"
      for INDEX in 1 2 3 4 5 6
      do
        # Проверяем, доступно ли блочное устройство
        aoeping -s 20 ${INDEXF} ${INDEXS} ${INTERFACE}
        if [ "$?" != "0" ]
        then
          let RETCOUNT=${RETCOUNT}+1
        fi
        echo "$?" >> ${LOG}
      done

     # Вылавливаем значение количества ошибок: "больше либо равно"
     if [ "${RETCOUNT}" -ge "5" ]
      then
        # Паникуем по поводу недоступности импортируемого устройства
        send-report "${OBJECT}" "Panic! Импортируемое блочное устройство обнаружено, но не доступно."
        echo >&2 "Panic! Импортируемое блочное устройство /dev/etherd/${OBJECT} обнаружено, но не доступно."
        return 1
      fi
    fi
  done
return 0
}

function start() {
  # Тестируем AoE-устройства в ожидании полного набора
  check-import
  RETAOE=$?

  # Проверяем, как успешно прошли тесты
  if [ "${RETAOE}" = "0" ]
  then
    echo "AoE driver initialization and test remote block devices complete."

    # Запускаем сбор файловой системы
    /etc/custom/hdd/mnt/assembly-mnt.sh

    # После сбора файловой системы запускаем пакет приложений, который на таковой работает
    /etc/init.d/application0 start
    /etc/init.d/application1 start
    /etc/init.d/application2 start
  else
    # Удаляем флаг блокировки во время исполнения
    rm --force /tmp/custom/aoe/lock
    exit 1
  fi
return 0
}

function stop() {
  # Останавливаем пакет приложений, который работает на сборной файловой системе
  /etc/init.d/application0 stop
  /etc/init.d/application1 stop
  /etc/init.d/application2 stop

  # Разбираем файловую систему, освобождая её ресурсы
  /etc/custom/hdd/mnt/disassembly-mnt.sh

  # Останавливаем работу AoE
  modprobe -r aoe
  echo "Wait..."
  sleep 3
  if [ -e /dev/etherd/discover ]
  then
    # Паникуем по поводу того, что модуль AoE не был выгружен несмотря на явное указание
    send-report "AoE" "Warning! Модуль AoE не был выгружен, несмотря на явное указание."
    echo >&2 "Warning! Модуль AoE не был выгружен, несмотря на явное указание."
    return 1
  fi
return 0
}

# Проверяем, не установлены ли флаги блокировки от текущего уровня схемы
if [ -e /tmp/custom/aoe/lock ]
then
  exit 0
fi

# Устанавливаем флаг блокировки на время работы скрипта
mkdir -p /tmp/custom/aoe
touch /tmp/custom/aoe/lock

case "$1" in
  start)
    start
  ;;
  stop)
    stop
  ;;
  restart)
    stop
    echo "Wait..."
    sleep 1
    start
  ;;
  check)
    # Тестируем подсистему MHDDFS
    check-mhddfs
    RETMHDDFS=$?

    # Тестируем существующую подсистему AoE
    check-import
    RETAOE=$?

    # В случае обнаружения несоответствия требуемому - перезапускаем сборку
    if [ "${RETMHDDFS}" != "0" ] || [ "${RETAOE}" != "0" ]
    then
      stop
      echo "Wait..."
      sleep 1
      start
    fi
  ;;
  *)
    echo "Usage $0 {start|stop|restart|check}" >&2
    # Удаляем флаг блокировки во время исполнения
    rm --force /tmp/custom/aoe/lock
    exit 1
  ;;
esac

# Удаляем флаг блокировки во время исполнения
rm --force /tmp/custom/aoe/lock

exit 0

После отработки публикующего (экспортирующего) скрипта в директориях "/dev/etherd/" всех компьютеров в одном сегменте сети Ethernet с запущенным AoE можно будет обнаружить ссылки на автоматически обнаруженные блочные устройства AoE, например:

# ls -l /dev/etherd/ | grep b

....
brw-rw--- 1 root disk 152, 16 2010-05-31 17:25 e0.1
brw-rw--- 1 root disk 152, 48 2010-05-31 17:25 e0.3
....
brw-rw--- 1 root disk 152, 48 2010-05-31 17:25 e4.7
....

Теперь нужно сделать так, что бы наш скрипт запускался при старте системы, причём пораньше, но после старта основных сервисов. Система инициализации Debian отрабатывает скрипты "/etc/init.d/*" по ссылкам в директории соответствующего "ранлевела" (для Debian Lenny/Squeeze это второй уровень исполнения), последовательно, приступая к делу с тех, что начинаются с буквы "K" (условно "kill"), посылая им аргумент "stop", и заканчивая исполнением тех, что начинаются с буквы "S" (условно "start"), посылая им аргумент "start". Подсмотрим, какой порядковый номер у ссылки на сценарий запуска сервиса SSH - "S18", я подумал, что для скрипта запуска сборки файловой системы номер "S19" будет в самый раз; срузу после SSH, если что - сможем посмотреть, что к чему.

Прописываем наш скрипт для нужных уровней исполнения в системе:

# update-rc.d aoe-import start 18 2 3 4 5 . stop 18 0 1 6 .

Размещаем команду запуска скрипта периодической проверки состояния в таблице /etc/crontab:

# vi /etc/crontab

....
*/7  * * * *  root  /etc/init.d/aoe-import check &
....


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )