обновление серверов через 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. Как минимум, вот такие:
Создавайте ваши runbook-и максимально гибкими. Это необходимо и для переноса в другие среды, и для простоты обслуживания их в дальнейшем. Представьте ситуацию, что у вас 100 runbook-ов, в которых вы используете activity Send Mail и жестко прописали smtp сервер. Сколько у вас займет времени и сколько вы допустите ошибок, если будет нужно его изменить? В случае же использования variables, достаточно ОДНОГО единственного изменения. Вот так, например, должен выглядеть ваш activity.
И еще очень важное применение variables — это хранение паролей. Объяснять, я думаю, излишне. И вы можете использовать переменную абсолютно везде.
Итак наш первый крупный блок — это Проверка на наличие обновлений.
Как я ранее писал, не жалейте пять минут и создавайте понятную и логичную иерархию папок. Согласно плану из второй части у нас будет такая вот иерархия:
В папке Проверка на наличие обновлений у нас будет 2 runbook-а. Первый формирует список серверов и запускает 2-й runbook (проверку на каждом сервере из списка). Запуск проверки происходит практически параллельно. Т.е. если у вас 150 серверов в списке, и самая длительная проверка занимает 3 минуты, то через 3 минуты у вас в базе появится информация о всех 150 серверах. Не забывайте об ограничении на одновременное количество выполняемых runbook-ов.
Начнем со второго runbook-а — нашей рабочей лошадки. Я дал ему название Проверка о доступных обновлениях на удаленном сервере.
Первая activity — Initialize Data. Единственный параметр, который мы передаем в этот runbook, имя сервера.
Следующая 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.
Из этой activity мы возвращаем следующие published data:
Два Link с названием Error имеют одинаковый фильтр Include и Exclude (он нужен, так как в следующих за этими link-ми activity используют published data из powershell скрипта).
Первый link ведет к activity Send Platform Event. Для того чтобы вы могли увидеть, что что-то пошло не так, в events самого Orchestrator-a. В activity вы можете выбрать ту информацию, которая вам нужна. Я бы остановился на имени сервера и всех данных из powershell скрипта.
Второй 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'
Теперь переходим к link-у Update info in SQL:
Если 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] =''
Подставьте значения следующим образом:
Проверка на ошибку:
И последующая запись в events:
Последний штрих в настройке самого runbook. Разрешим ему работать параллельно. В свойствах runbook-а на вкладке Job Concurrency укажем вместо единицы двести:
Указывая это число, вы должны понимать, что даже в случае, когда на вашем runbook сервере ничего, кроме процесса обновлений работать не будет, 200 одновременных проверок у вас не получится. Максимум 199, так как 1 процесс уже занят runbook-ом, который и запускает эти проверки. А если у вас много различных работающих runbook-ов, то число одновременных проверок будет еще меньше.
Теперь разберем runbook, который будет вызывать уже рассмотренный выше Проверка о доступных обновлениях на удаленном сервере.
Его название Получаем список серверов на обновление.
Как видим, простейший 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.
Link ListOfServers, который соединяет эти activity, имеет следующий фильтр. Количество записей, которые возвращаются, больше нуля:
Activity Invoke Runbook.
В поле runbook выбираете уже созданный runbook Проверка о доступных обновлениях на удаленном сервере.
А в parameters указываете функцию [field(param1,’;’,1)], где вместо param1 вставьте:
И последний этап — это добавление необходимых activity с проверками на ошибки. Детально рассматривать их не буду. Никаких трудностей с ними у вас возникнуть не должно.
Единственный вопрос, который остался открытым, это как же будет запускаться этот runbook? Никаких activity типа monitor здесь нет. Мы решили, что проверка должна стартовать каждый день в 07:00. Об этом и о небольшом runbook-e, выполняющем рассылку оповещения о предстоящих работах, я расскажу в четвертой части. Долго ждать не придется.
Оставайтесь с нами. Пишите комментарии. Дальше будет интереснее!
Александр Петлевой
Спасибо за статью.
Было бы круто, например, чтобы в теле письма, о том что нашлись обновления, была управляющая кнопка с функцией что-то типо «отложить на сутки»
Я думаю можно реализовать такую кнопку. Как вариант создать web приложение, а в теле письма делать ссылку с параметрами имя сервера и т.п. А кнопка обновит запись в БД. Например, переставит на день +1.
Но я очень НЕ РЕКОМЕНДОВАЛ это делать. У вас должен быть четко определенный регламент на проведение работ. Если по каким-то причинам нужно запретить выполнение работ, просто поставте в поле Type = ‘Manual’.
Александр, а можно подробней про Initialize Data. Какие еще варианты есть передачы данных в Initialize Data?
Например, если в пакете для sharepoint я использую возможность мониторинга списков, вставляю объект в ранбук, который раз в минуту подключается к шарику, проверяет список, если была создана в списке запись, он забирает все данные и дальше по ранбуку уже в published data я ими оперирую как хочу, то я не могу понять, а как данные попадают в Initialize Data. Ну вот мы объявили servername, а его имя то мы как передаем в ранбук? Ну удаленно пнули службу, что запусти нам ранбук вот с таким айди. Мы прямо в запросе переменную передаем? Или берем какую-то подбную конструкцию Get-WMIObject Win32_ComputerSystem | Select-Object -ExpandProperty name?
да и по статье, я так и не понял «Первая activity — Initialize Data. Единственный параметр, который мы передаем в этот runbook, имя сервера». Может я что-то пропустил, ткните пальцем.
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. ясно-понятно.