Управляем серверами в реальном времени с помощью WSH-сценариев::Журнал СА 10.2005
www.samag.ru
Льготная подписка для студентов      
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
О журнале
Журнал «БИТ»
Подписка
Где купить
Авторам
Рекламодателям
Магазин
Архив номеров
Вакансии
Контакты
   

Jobsora

ЭКСПЕРТНАЯ СЕССИЯ 2019


  Опросы

Какие курсы вы бы выбрали для себя?  

Очные
Онлайновые
Платные
Бесплатные
Я и так все знаю

 Читать далее...

1001 и 1 книга  
28.05.2019г.
Просмотров: 1894
Комментарии: 2
Анализ вредоносных программ

 Читать далее...

28.05.2019г.
Просмотров: 1936
Комментарии: 1
Микросервисы и контейнеры Docker

 Читать далее...

28.05.2019г.
Просмотров: 1497
Комментарии: 0
Django 2 в примерах

 Читать далее...

28.05.2019г.
Просмотров: 1098
Комментарии: 0
Введение в анализ алгоритмов

 Читать далее...

27.03.2019г.
Просмотров: 1667
Комментарии: 1
Arduino Uno и Raspberry Pi 3: от схемотехники к интернету вещей

 Читать далее...

Друзья сайта  

Форум системных администраторов  

sysadmins.ru

Электронка - 2020!

 Управляем серверами в реальном времени с помощью WSH-сценариев

Архив номеров / 2005 / Выпуск №10 (35) / Управляем серверами в реальном времени с помощью WSH-сценариев

Рубрика: Программирование /  Автоматизация   | Дополнительные материалы

АНДРЕЙ БИРЮКОВ

Управляем серверами в реальном времени с помощью WSH-сценариев

Проблемы, связанные с перебоями электроснабжения, уже давно являются головной болью для системных администраторов и специалистов по обслуживанию сети. Системы, предлагаемые компаниями-производителями, не всегда полностью отвечают необходимым требованиям. Сегодня мы расскажем вам, как использовать WSH-сценарии для взаимодействия серверов с системами бесперебойного питания.

Вместо предисловия

На тему использования различных сценариев в задачах системного администрирования уже написана масса всевозможных статей. Особенно это касается Linux/UNIX-операционных систем, обладающих мощными языками сценариев, которые позволяют выполнять большое количество различных административных задач.

А что же Windows? В Windows имеется WSH – Windows Script Host, это основной инструмент для всех административных сценариев, поскольку все административные сценарии выполняются внутри WSH. Сценарии WSH можно писать на языках Jscript .NET, VBScript, Perl, Python и REXX. В данной статье все примеры сценариев приводятся на VBScript.

Документация по WSH предлагает использовать сценарии преимущественно для сбора информации о системе, работы с файловой системой или изменении различных системных настроек. Однако сегодня мы поговорим об использовании сценариев для автоматизированного мониторинга и управления Windows-серверами.

Постановка задачи

Причина, по которой возникла необходимость в написании сценария для автоматизированного управления Windows-серверами, довольно проста, особенно в свете недавних проблем с подачей электропитания. У заказчика имелось несколько серверов Windows 2003, и требовалось организовать бесперебойное электропитание на основе APC UPS. В комплекте с UPS поставлялось программное обеспечение, в состав которого входил агент для взаимодействия с UPS. Один из серверов подключался к источнику бесперебойного питания через COM-порт и на этом сервере был установлен агент, который в случае отключения питания должен был корректно завершить работу сервера. А вот на остальных серверах такой агент без подключения к источнику через СОМ-порт не работал, и следовательно, эти сервера в случае исчезновения питания проработали бы ровно столько, насколько хватило бы заряда аккумулятора, а потом просто отключатся, что, очевидно, совсем не хорошо. Компания-производитель предлагает в качестве решения проблемы приобрести специальное оборудование, проще говоря, СОМ-свитч, однако в силу ряда причин нас подобный вариант не устроил.

Тогда и был написан сценарий на VBScript, который отслеживал в журнале событий появление сообщения об отключении питания на том сервере, где установлен агент, и затем, если по прошествии некоторого периода времени питание не восстанавливалось, начинал корректно выключать сервера, при этом отправляя администратору письмо по электронной почте с уведомлением об отключении.

На примере такого сценария мы и рассмотрим реализацию задачи управления серверами с помощью VBScript. Думаю, примеры программ и методы работы, изложенные в статье, могут быть полезны не только при решении описанной проблемы, но также и для других задач автоматизации системного администрирования в реальном времени. Итак, приступим к реализации. Прежде всего создадим текстовый файл с расширением vbs. Для выполнения сценария достаточно будет лишь запустить созданный vbs-файл.

Читаем журнал событий (Event Log)

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

Рисунок 1. Журнал событий Event Log, содержащий сообщения от агента источника бесперебойного питания

Рисунок 1. Журнал событий Event Log, содержащий сообщения от агента источника бесперебойного питания

При отключении питания в журнале событий появляется сообщение следующего вида (см. рис. 2).

Рисунок 2. Сообщение об отключении основного питания

Рисунок 2. Сообщение об отключении основного питания

При восстановлении питания агент создаст в журнале событий следующее сообщение (см. рис. 3).

Рисунок 3. Сообщение о восстановлении основного питания

Рисунок 3. Сообщение о восстановлении основного питания

Итак, мы определили, как выглядят сообщения, отправляемые агентом источника бесперебойного питания. В журнале событий нам необходимо искать сообщения с полем Description вида: «UPS On Battery» или «Utility Power Restored», которые будут сигнализировать о потере питания и его восстановлении соответственно.

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

Листинг 1. Поиск сообщений в журнале событий

Option Explicit

Dim objWMI, objItem ' Objects // Объявляем переменные

Dim strComputer

Dim  intRecordNum, intRec, colLoggedEvents

Dim strAdmin, strAdmin2, i, intrecordNum2, iteration

' WMI Core Section

// Сервер, на котором выполняется сценарий

strComputer="127.0.0.1"

Set objWMI = GetObject("winmgmts:" _

& "{impersonationLevel=impersonate}!\\" _

& strComputer & "\root\cimv2")

iteration=2 // счетчик итераций

// искомые строки – отключение питания

strAdmin = "UPS On Battery"

// искомые строки – восстановление питания

strAdmin2 = "Utility Power Restored"

Do While 1=1 // цикл бесконечный

    // запрос по журналу событий. Раздел Applications

    Set colLoggedEvents = objWMI.ExecQuery ("Select * from Win32_NTLogEvent Where Logfile = 'Application'" )

    // счетчики записей

    intRecordNum=0 // счетчик найденных записей

    intRec=0 // счетчик всех записей

    intRecordNum2=0

       For Each objItem in colLoggedEvents

           // ищем первое вхождение записи

           // на отключение

           If intRecordNum=0 Then

           If InStr(1,objItem.message,strAdmin,1) Then intRecordNum = intRec+1

           End If

           // ищем первое вхождение записи

           // на восстановление

           If intRecordNum2=0 Then

           If InStr(1,objItem.message,strAdmin2,1) Then intRecordNum2 = intRec +1

           End If

           intRec=intrec+1

           // если все нашли, выходим из цикла

           If intRecordNum>0 AND intrecordNum2>0 Then Exit For

       Next

       / если не нашли записей об отключении,

       // то и записи о восстановлении не нужны

       If intrecordNum=0 Then intRecordNum2=0

       If iteration=0 Then    

       shutdown 

       // а здесь будет находиться ссылка на процедуру

       // отключения питания на других серверах

       End If

       If intrecordNum<intrecordNum2  Then

           iteration=iteration-1

       End If

       If intrecordNum2=0  Then

           If intRecordNum>0 Then iteration=iteration-1

       End If

    loop

WScript.Sleep 10000 // Задержка перед следующей итерацией

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

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

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

Также следует обратить внимание на последнюю команду сценария, которая определяет период бездействия цикла перед выполнением итерации, в миллисекундах. Указанный в листинге интервал в десять секунд на практике скорее всего окажется крайне мал. Опыт показывает, что интервал должен быть не менее минуты, так как уже в течении одной минуты любой источник бесперебойного питания просто обязан держать напряжение. К тому же поиск по всему журналу событий может отнимать довольно значительные ресурсы системы. Для борьбы с этим можно рекомендовать понизить приоритет процесса со «среднего» на «ниже среднего».

Вообще читателю, искушенному в программировании, алгоритм, приведенный в Листинге 1, может показаться немного странным и нуждающимся в доработке. Такое мнение будет вполне справедливо, так как, составляя алгоритм, я, основываясь на своем опыте, сделал ряд допущений, тем самым существенно его упростив и сделав более удобочитаемым, не в ущерб качеству. Но, возможно, в вашем конкретном случае потребуется что-либо доработать или исправить. Однако продолжим, следующим этапом у нас будет процедура отключения питания.

Отключаем сервера

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

Я бы очень не рекомендовал использовать для этих целей учетную запись администратора, так как в исходном тексте необходимо указать пароль учетной записи, которая используется для выполнения отключения. Также из соображений безопасности необходимо ограничить доступ к данному сценарию так, чтобы его могли читать/запускать только администраторы. Подобная настройка выходит за рамки данной статьи, однако я думаю, что любой системный администратор без труда справится с этой задачей.

Листинг 2. Процедура отключения питания

Sub Shutdown

On Error Resume Next // если ошибка, переходим к следующему

Dim arrComputers, objLocator

Dim login, password, domain

// Перечисляем имена серверов, которые должны быть выключены

 arrComputers = Array("Computer1","Computer2","Computer3")

login="operator" // учетная запись с правом на shutdown

password="password" // пароль

domain="TEST" // домен

For Each strComputer In arrComputers

    Set objLocator = CreateObject("WbemScripting.SWbemLocator")

    Set objWMIService = objLocator.ConnectServer(strComputer, "root\cimv2", login, password, domain)

    Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")

    For Each objOperatingSystem in colOperatingSystems

           // непосредственно shutdown

           ObjOperatingSystem.Shutdown(1)

    Next

    // после отключения уведомим администратора

    sendmail(strComputer)     

Next

WScript.Quit // сценарий завершает свою работу

End Sub

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

Также в тексте мы встречаем упоминание о процедуре отправки сообщений администратору или службе технической поддержки. В качестве параметра данной процедуре передается имя отключенного сервера.

Рассмотрим процесс отправки уведомлений более подробно.

Отправляем уведомления

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

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

Итак, обосновав необходимость отправки уведомления, приступим к описанию практической реализации. Современные технологии связи позволяют различные способы уведомления администратора о различных событиях в сети. Например, мне приходилось слышать о системе, которая в случае возникновения внештатной ситуации звонила админу по заранее заданному телефону и проигрывала mp3-файл, содержавший голосовую информацию. Но в такие крайности мы вдаваться не будем – отправим уведомление при помощи электронной почты. В принципе, с помощью того метода, который будет описан далее, наверняка можно отправлять и ICQ-сообщения и даже SMS (хотя из-за различных ограничений, введенных операторами сотовой связи, это сделать будет крайне затруднительно).

Раньше для отправки сообщений посредством сценариев Windows использовался почтовый клиент Outlook. При этом применялся сценарий следующего вида:

Листинг 3. Отправка письма с помощью Outlook

Dim OutlookObject, OutMail

Set OutlookObject = CreateObject("Outlook.Application")

Set OutMail = OutlookObject.CreateItem(0)

OutMail.to = "test@test.ru"

OutMail.Subject = "Тема сообщения"

OutMail.Body = "Тело сообщения"

OutMail.Send

Рисунок 4. Запрос на отправку сообщения

Рисунок 4. Запрос на отправку сообщения

К тому же практически любой антивирус заблокирует работу сценария.

По понятным причинам нас это совершенно не устраивает. Но существует другой способ отправки почтовых сообщений сценарием. Данная процедура была найдена мной в MSDN [1].

Листинг 4. Отправка письма

// Получаем в качестве параметра имя сервера

Sub sendmail(server)

// Инициализируем переменные

Dim iMsg

Dim iConf

Dim Flds

Dim str

Const cdoSendUsingPickup = 1

Set iMsg = CreateObject("CDO.Message")

Set iConf = CreateObject("CDO.Configuration")

// Подготавливаем поля для отправки по SMTP

Set Flds = iConf.Fields

With Flds

    .Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = cdoSendUsingPickup

    .Item("http://schemas.microsoft.com/cdo/configuration/smtpserverpickupdirectory") = "c:\inetpub\mailroot\pickup"

    .Update

End With

// Непосредственно текст сообщения

str= "Уважаемый администратор. Сервер  " & server & " был отключен "& Now &" в связи с потерей электропитания. "

// заполоняем все поля сообщения

With iMsg

    Set .Configuration = iConf

    .To = "admin@server.com"  // Поле «Кому»

    .From = "ups@example.com" // Поле «От кого»

    // Тема письма

    .Subject = "Отключение питания на сервере " & server 

    .HTMLBody = str

    .Send

End With

// Очищаем переменные

Set iMsg = Nothing

Set iConf = Nothing

Set Flds = Nothing

End Sub

Данная процедура отправит письмо по указанному адресу. В результате получателю придет сообщение примерно следующего содержания:

Уважаемый администратор. Сервер  MyServer  был отключен 01.10.2005 23:03:31 в связи с потерей электропитания.

При необходимости процедуру можно легко подправить, для того чтобы отправлялось сразу несколько писем различным адресатам.

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

Также хотелось бы обратить ваше внимание еще на один щекотливый момент. В случае восстановления питания необходимо снова включить отключенные сервера. Для этого прежде всего надо в BIOS каждого из серверов установить свойство «Wake Up On LAN  ON». Я не думаю, что это может создать какие-то трудности в повседневной работе хотя бы потому, что сервера должны быть всегда включены, их не выключают на ночь. Теперь нам необходимо создать какой-либо трафик с помощью нашего сценария. Сделать это можно с помощью фрагмента одной из процедур, описанной ранее. Далее приводится фрагмент Листинга 1, в котором при обнаружении сообщения о восстановлении питания вызывается процедура WakeUp, осуществляющая пинг каждого из серверов (Листинг 6 соответственно). Обратите внимание на использованный в Листинге 6 метод Run. С помощью него можно выполнить любую команду, причем (как показано в Листинге 6) это делается в режиме hide. Если в вашем случае необходимо видимое окно, просто в качестве второго параметра для метода Run укажите единицу. Более подробное описание данного метода и его параметров можно найти в [1].

Листинг 5. Добавление вызова процедуры Wakeup в сценарий Листинга 1

……………..

// Ищем первое вхождение записи на восстановление

If intRecordNum2=0 Then

If InStr(1,objItem.message,strAdmin2,1)  Then intRecordNum2 = intRec +1

WakeUp

End If

…………..

Листинг 6. Процедура WakeUp

Sub WakeUp

On Error Resume Next // если ошибка, переходим к следующему

Dim arrComputers

Dim WshShell, str

// Перечисляем имена серверов, которые должны быть выключены

arrComputers = Array("Computer1","Computer2","Computer3")

Set WshShell = CreateObject("WScript.Shell")

For Each strComputer In arrComputers

    str="ping "& strComputer

    //запускаем в режиме hide

    Return = WshShell.Run(str, 0)

Next

End Sub

Заключение

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

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

Ссылка:

  1. http://msdn.microsoft.com – содержит много примеров с исходными текстами сценариев.

Комментарии
 
  03.12.2010 - 02:28 |  Alexander Cherepnev

Статья неплохая. Только скрипты конечно требуют глобальной переделки. К примеру в приведенном скрипте сценарий читает ВСЕ данных из ВСЕХ записей журнала Applications (Приложеения). На мой взгляд это примерно то же самое что читать всю энциклопедию в поисках статьи про самолет. Что мешало автору внести дополнительное условие в текст запроса. Это ЗНАЧИТЕЛЬНО снизит трафик и соответственно загрузку процессора. Во вторых задержка между интерациями почему то находится ВНЕ цикла. Так этот скрипт будет ПОСТОЯННО перечитывать журнал, не делая пауз...
Ну и наконец: Я не советую делать WakeUp on Lan. Вернее не в данном случае. Представьте себе, отключился свет, сценарий отработал отключение серверов... Все хорошо, но вдруг по сети проходит какой нибудь шальной пакет, например от какого нибудь юзера, или из интернета. Не суть важно откуда - но он пришел. И Ваш сервер включится, начнет грузиться и отрубится когда отключится питание UPS. Причем Ваш скрипт будет абсолютно уверен что сервер был выключен нормально. Вот такая вот грустная история...
А так, статья неплохая... :)

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru