обновление серверов через Orchestrator 2012 (часть 3)

Привет.

Первая часть

Вторая часть

В первой и второй части мы обсудили различные моменты нашего процесса обновления серверов. Давайте же перейдем в конце концов к Orchestrator-у.

Начнем с настройки Orchestrator-a.

На каждом Runbook сервере по умолчанию одновременно могут работать 50 runbook-ов. Увеличим это количество до 200, если серверов на обновление у вас очень много, это значение должно быть еще больше.
cd <System Drive>:\Program Files (x86)\Microsoft System Center 2012\Orchestrator\Management Server

aspt * 200

И перезапуск Orchestrator Runbook Service.

Теперь давайте создадим несколько глобальных переменных. Мы будем их использовать в наших runbooks. Как минимум, вот такие:

OpalisUpdate001

Создавайте ваши runbook-и максимально гибкими. Это необходимо и для переноса в другие среды, и для простоты обслуживания их в дальнейшем. Представьте ситуацию, что у вас 100 runbook-ов, в которых вы используете activity Send Mail и жестко прописали smtp сервер. Сколько у вас займет времени и сколько вы допустите ошибок, если будет нужно его изменить? В случае же использования variables, достаточно ОДНОГО единственного изменения. Вот так, например, должен выглядеть ваш activity.

OpalisUpdate002

 

И еще очень важное применение variables — это хранение паролей. Объяснять, я думаю, излишне. И вы можете использовать переменную абсолютно везде.

OpalisUpdate003

Итак наш первый крупный блок — это Проверка на наличие обновлений.

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

OpalisUpdate004

В папке Проверка на наличие обновлений у нас будет 2 runbook-а. Первый формирует список серверов и запускает 2-й runbook (проверку на каждом сервере из списка). Запуск проверки происходит практически параллельно. Т.е. если у вас 150 серверов в списке, и самая длительная проверка занимает 3 минуты, то через 3 минуты у вас в базе появится информация о всех 150 серверах. Не забывайте об ограничении на одновременное количество выполняемых runbook-ов.

Начнем со второго runbook-а — нашей рабочей лошадки. Я дал ему название Проверка о доступных обновлениях на удаленном сервере.

Обновлениесерверов014

 

Первая activity — Initialize Data. Единственный параметр, который мы передаем в этот runbook, имя сервера.

OpalisUpdate007

Следующая activity — это скрипт на powershell Check Updates on Remote Server. И тут важный момент: все сервера, на которых вы планируете устанавливать обновления, должны удаленно управляться через WinRM.

Также учетная запись, от которой работает служба Orchestrator Runbook Service, должна иметь права на доступ к серверу и установку обновлений. Другой вариант — это использование с командлетом New-PSSession параметра -Credential. Тут не забывайте про использование переменных для хранения пароля. В этой демонстрации учетная запись имеет необходимый доступ на сервера и -Credential не используется

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

$ServerName = "Insert publish data ServerName"
$ErrorState = 0
$ErrorMessage = ""
$Trace = ""
$Error.Clear()
if ($ServerName.length -lt 1)
{
Throw "Error: One or more required parameters is Null."
}
$Session = New-PSSession -ComputerName $ServerName
if ($Session -eq $null)
{
$ErrorMessage = $Error[0]
$Trace += "Could not create PSSession on $ServerName"
$ErrorState = 2
}
else
{
$ReturnArray = Invoke-Command -Session $Session -Argumentlist $ServerName -ScriptBlock {
Param ( $ServerName )
Try
{
$Action = 'Check Server for available updates';
$Trace = "Beginning remote action '$Action' 'r'n"
$Trace += "Parameters:'r'n"
$Trace += " ServerName: $ServerName 'r'n"
$Trace += "'r'n"

$p_updateSession = new-object -com "Microsoft.Update.Session"
$p_updates=$p_updateSession.CreateupdateSearcher().Search($criteria).Updates
if(($p_updates.count -gt 0) -and ($p_updates))
{
$Trace += $p_updates | select title | out-string
$Trace += "'r'n"
$NeedInsertInList = 1
}
else
{
$Trace += "No available updates"
$Trace += "'r'n"
$NeedInsertInList = 0
}
$ErrorState = 0 #Return Success
$Trace += "Completed remote action '$Action'... 'r'n"
}
Catch
{
$Trace += "Exception caught in remote action '$Action'... 'r'n"
$ErrorState = 2
$ErrorMessage = $error[0].Exception.tostring()
}
Finally
{
$Trace += "Exiting remote action '$Action' 'r'n"
$Trace += "ErrorState: $ErrorState'r'n"
$Trace += "ErrorMessage: $ErrorMessage'r'n"
}
$Results = @($ErrorState, $ErrorMessage, $Trace,$NeedInsertInList)
Return $Results
}

$ErrorState = $ReturnArray[0]
$ErrorMessage = $ReturnArray[1]
$Trace = $ReturnArray[2]
$NeedInsertInList = $ReturnArray[3]
Remove-PSSession -Session $Session
}

Обратите внимание на первую строку. После того, как вы вставили скрипт в поле script, подставьте ServerName из предыдущей activity Initialize Data.
OpalisUpdate008

Из этой activity мы возвращаем следующие published data:

OpalisUpdate009

Два Link с названием Error имеют одинаковый фильтр Include и Exclude (он нужен, так как в следующих за этими link-ми activity используют published data из powershell скрипта).

OpalisUpdate010_1OpalisUpdate010_2

Первый link ведет к activity Send Platform Event. Для того чтобы вы могли увидеть, что что-то пошло не так, в events самого Orchestrator-a.  В activity вы можете выбрать ту информацию, которая вам нужна. Я бы остановился на имени сервера и всех данных из powershell скрипта.

OpalisUpdate011

Второй link ведет к записи в базу данных о ошибках, которые произошли при выполнении. Идет запись в базу информации об ошибке Write Error In DB (activity Query Database). Удобно сделать отчет по расписанию и видеть общую картину. Потому что и WinRM иногда слетает, и доступ пропадает  😉 .

Query:

update [dbo].[t_Orch_Patching_Server]
set [error] = 'Вставить published data из Check Updates on Remote Server',
[errormesg]='Вставить published data из Check Updates on Remote Server'
where [ServerName] ='Вставить published data из Initialize Data'

OpalisUpdate013

Теперь переходим к link-у Update info in SQL:

OpalisUpdate014

OpalisUpdate015

OpalisUpdate016

Если activity Check Updates on Remote Server не вернула ErrorState=2 и отработала без ошибок, значит, проверка на наличие обновлений отработала, и можно поместить информацию в базу данных.

И делает это следующая activity Update NeedToUpdate Field (activity Query Database)

Query

update [dbo].[t_Orch_Patching_Server]
set [NeedToUpdate] = '',
[Error] = '',
ErrorMesg ='',
LastCheckTime = GETDATE()
where [ServerName] =''

Подставьте значения следующим образом:

OpalisUpdate017

Проверка на ошибку:

Обновлениесерверов015

И последующая запись в events:

Обновлениесерверов016

Последний штрих в настройке самого runbook. Разрешим ему работать параллельно. В свойствах runbook-а на вкладке Job Concurrency укажем вместо единицы двести:

Обновлениесерверов017

Указывая это число, вы должны понимать, что даже в случае, когда на вашем runbook сервере ничего, кроме процесса обновлений работать не будет, 200 одновременных проверок у вас не получится. Максимум 199, так как 1 процесс уже занят runbook-ом, который и запускает эти проверки. А если у вас много различных работающих runbook-ов, то число одновременных проверок будет еще меньше.

Теперь разберем runbook, который будет вызывать уже рассмотренный выше Проверка о доступных обновлениях на удаленном сервере.

Его название Получаем список серверов на обновление.
OpalisUpdate005

Как видим, простейший runbook.

Но перед тем, как мы его рассмотрим, я хочу внести изменения в базу данных. В процессе реализации я понял, что использовать названия дней недели на английском не очень удобно для последующей рассылки, поэтому давайте расширим поле [DayOfWeek] [nvarchar](10) до 20 хранимых знаков. И заменим, для примера, monday на понедельник. Остальные дни замените сами.

ALTER TABLE [dbo].[t_Orch_Patching_Server]
ALTER COLUMN [DayOfWeek] nvarchar(20)

UPDATE [dbo].[t_Orch_Patching_Server]
SET [DayOfWeek] = N'понедельник'
WHERE [DayOfWeek] = N'monday'

Продолжаем с Orchestrator-ом.

Основную работу выполняет Query Database.

В поле Query введем

set language russian

IF DATENAME(weekday, getdate()) <>  N'пятница'

select
servername,
descr,
convert(date,DATEADD(dd,1,getdate())) as NextDay,
[time],
[DayOfWeek],
[EndTime],
[E-mail business]
from [dbo].[t_Orch_Patching_Server]
where DayOfWeek = DATENAME(weekday, DATEADD(dd,1,getdate()))
ELSE
select
servername,
descr,
CASE [DayOfWeek]
WHEN N'суббота' THEN convert(date,DATEADD(dd,1,getdate()))
WHEN N'воскресенье' THEN convert(date,DATEADD(dd,2,getdate()))
WHEN N'понедельник' THEN convert(date,DATEADD(dd,3,getdate()))
END as NextDay,
[time],
[DayOfWeek],
[EndTime],
[E-mail business]
from [dbo].[t_Orch_Patching_Server]
where [DayOfWeek] in (DATENAME(weekday, DATEADD(dd,1,getdate())),DATENAME(weekday, DATEADD(dd,2,getdate())),DATENAME(weekday, DATEADD(dd,3,getdate())))

Данный запрос выдает список серверов, у которых обслуживание завтра. Но если сегодня пятница, то к завтра (субботе) добавляется воскресенье и понедельник.

После  Query Database мы используем activity Invoke Runbook.

Обновлениесерверов018

Link ListOfServers, который соединяет эти activity, имеет следующий фильтр. Количество записей, которые возвращаются, больше нуля:

Обновлениесерверов019

Activity Invoke Runbook.

В поле runbook выбираете уже созданный runbook Проверка о доступных обновлениях на удаленном сервере.

Обновлениесерверов020

А в  parameters указываете функцию  [field(param1,’;’,1)], где вместо param1 вставьте:
Обновлениесерверов021

И последний этап — это добавление необходимых activity с проверками на ошибки. Детально рассматривать их не буду. Никаких трудностей с ними у вас возникнуть не должно.

Единственный вопрос, который остался открытым, это как же будет запускаться этот runbook? Никаких activity типа monitor  здесь нет. Мы решили, что проверка должна стартовать каждый день в 07:00. Об этом и о небольшом runbook-e, выполняющем рассылку оповещения о предстоящих работах, я расскажу в четвертой части. Долго ждать не придется.

Обновлениесерверов023

Оставайтесь с нами. Пишите комментарии. Дальше будет интереснее!

Александр Петлевой

5 комментариев

  1. naezd:

    Спасибо за статью.
    Было бы круто, например, чтобы в теле письма, о том что нашлись обновления, была управляющая кнопка с функцией что-то типо «отложить на сутки»

    • it.resolve:

      Я думаю можно реализовать такую кнопку. Как вариант создать web приложение, а в теле письма делать ссылку с параметрами имя сервера и т.п. А кнопка обновит запись в БД. Например, переставит на день +1.
      Но я очень НЕ РЕКОМЕНДОВАЛ это делать. У вас должен быть четко определенный регламент на проведение работ. Если по каким-то причинам нужно запретить выполнение работ, просто поставте в поле Type = ‘Manual’.

  2. Александр, а можно подробней про Initialize Data. Какие еще варианты есть передачы данных в Initialize Data?
    Например, если в пакете для sharepoint я использую возможность мониторинга списков, вставляю объект в ранбук, который раз в минуту подключается к шарику, проверяет список, если была создана в списке запись, он забирает все данные и дальше по ранбуку уже в published data я ими оперирую как хочу, то я не могу понять, а как данные попадают в Initialize Data. Ну вот мы объявили servername, а его имя то мы как передаем в ранбук? Ну удаленно пнули службу, что запусти нам ранбук вот с таким айди. Мы прямо в запросе переменную передаем? Или берем какую-то подбную конструкцию Get-WMIObject Win32_ComputerSystem | Select-Object -ExpandProperty name?
    да и по статье, я так и не понял «Первая activity — Initialize Data. Единственный параметр, который мы передаем в этот runbook, имя сервера». Может я что-то пропустил, ткните пальцем.

    • it.resolve:

      Initialize Data обычно работает в связке с Invoke Runbook. То есть главный runbook содержит Invoke Runbook, где указывается подчиненный runbook c activity Initialize Data. Мы сами определяем, какие параметры нужны для работы подчиненного runbook-a. И эти параметры будут видны из Invoke Runbook когда мы выберем подчиненный runbook. В runbook-е Получаем список серверов на обновление Initialize Data пустая. Ее можно и не создавать. А вот Invoke Runbook в этом же runbook-е и передает имя сервера подчиненному runbook-у (Проверка о доступных обновлениях на удаленном сервере.) А у него в Initialize Data — http://liashov.com/wp-content/uploads/2015/08/OpalisUpdate007.png

      • а, все работает от противного. )))
        то есть мы просто объявляем переменные, которые будем использовать в дальнейшем в скрипте, либо в published data. ясно-понятно.

Leave a Reply to Anton Masyan