понедельник, 3 сентября 2012 г.

Особенности управления крупной инфраструктурой. Переход

Замена ключевого компонента системы никогда не бывает безболезненным: всегда приходится идти на компромиссы, чем-то жертвовать, что-то доделывать. Принимаемые решения всегда балансируют между двумя противоположными целями: сделать правильно и добиться обратной совместимости, чтобы минимизировать потери времени и не навредить стабильности продукта. В итоге новый компонент частично обретает черты старого, где-то вынужденно повторяет его ошибки. Это неизбежная плата за возможность наиболее безболезненным образом исправить некоторый фатальный недостаток старого компонента, из-за которого и был затеян весь переход. Не стал исключением и наш Windows Provisioning Engine, о котором я начал рассказывать в прошлый раз. Если сравнить его с Microsoft Provisioning System, то можно обнаружить много общего.

До

Изначально в качестве системы управления мы использовали Microsoft Provisioning System – это решение компании Microsoft, как раз предназначенное для управления инфраструктурой поставщиков услуг. Если описывать её упрощённо, то эта система состояла из серверного компонента, принимающего запросы от контрольной панели, и набора провайдеров, каждый из которых реализовывал управляющие процедуры из какой-то конкретной предметной области. Так, например, провайдер Active Directory покрывал все аспекты управления организационными единицами, пользователями, группами и прочими объектами каталога. Система поставлялась с большим количеством готовых провайдеров и позволяла расширять их набор за счёт своих. SDK MPS`а первых версий позволял писать провайдеры исключительно на C++, в дальнейшем появилась возможность использовать .NET.

Серверный компонент, принимающий запросы, был реализован как DCOM сервер. В дальнейшем над ним появилась надстройка в виде Web-сервисов, но мы её никогда не использовали. Сам сервер не представлял из себя ничего примечательного. По сути это был DCOM объект, который помимо некоторого количества вспомогательных методов реализовывал метод SubmitRequest, именно он и позволял управлять всей инфраструктурой. Этот метод принимал в качестве строкового аргумента запрос, написанный на специальном языке. Именно этот язык и был самой примечательной частью всей системы. Он базировался на XML`е, но при этом содержал ряд характерных империческим языкам управляющих конструкций, таких как: цикл, ветвление, обработка исключений и так далее. Ниже приведён пример такого запроса, чтобы было легче себе представить, что это такое (обратите внимание на замечательный тэги foreach – вы никогда не видели цикла в XML – я прежде тоже Подмигивающая рожица):
<request>
 <data>
  <organizations>
    <organization name="tailspintoys.com" type="primary">
      <user name="joe"/>
      <user name="nancy"/>
    </organization>
    <organization name="wideworldimporters.com" type="primary">
      <user name="fred"/>
    </organization>
    <organization name="fourthcoffee.com" type="secondary">
    </organization>
    <organization name="adventure-works.com" type="secondary">
    </organization>
  </organizations>
 </data>
 <procedure>
  <execute namespace="Test Namespace" procedure="Write Request">
   <forEach
   
name="organization"
   
root="data"
   
path="organizations/organization"/>
   <forEach
   
name="user"
    
root="organization"
    
path="user"
    
ifNull="skip"/>
   <before source="organization" destination="executeData">
    <xsl:template match="organization[@type='primary']">
     <primaryOrg>
      <xsl:value-of select="@name"/>
     </primaryOrg>
    </xsl:template>
    <xsl:template match="organization[@type='secondary']">
     <secondaryOrg>
      <xsl:value-of select="@name"/>
     </secondaryOrg>
    </xsl:template>
   </before>
   <after
    
source="executeData"
   
destination="data"
   
destinationPath="orgSignup"
   
mode="merge"/>
  </execute>
 </procedure>
</request>

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

Функции этого языка не ограничивались лишь запросами к системе. Он использовался и в качестве языка сценариев для написания целых провайдеров наряду с такими компилируемыми языками как C++ и C#. И хотя возможности именно этих провайдеров (написанных на скриптовом языке) были ограниченны функционалом предоставляемым системой и её компонентами (в частности другими провайдерами), их главный плюс был в том, что они всегда поставлялись в открытом виде – это позволяло при необходимости вносить исправления прямо на месте, для быстрого решения проблем на развёрнутых инфраструктурах поставщиков услуг.

После
Как я уже говорил, у MPS есть один фатальный недостаток: её разработка и поддержка прекращена. Поэтому, когда в один прекрасный момент перед нами замаячила перспектива разработки собственной системы управления инфраструктурой, мы столкнулись с двумя принципиальными проблемами:
  1. Что взять за основу языка сценариев для разработки провайдеров?
  2. Как быть с наследием MPS`а, активно использующимся контрольной панелью?
С первой проблемой мы разобрались достаточно быстро и выбрали для наших целей язык PowerShell (о чём я достаточно подробно писал в прошлый раз). Со второй проблемой было всё не так просто, потому что мы использовали:
  1. Запросы на скриптовом языке MPS`а, формируемые контрольной панелью и отправляемые системе управления инфраструктурой.
  2. Собственные провайдеры, написанные на скриптовом языке MPS`а.
  3. Собственные провайдеры, написанные на компилируемых языках C# и C++.
Наиболее массивным и критическим куском функциональности были MPS запросы, формируемые контрольной панелью. Собственными провайдерами мы могли спокойно пожертвовать, переписав их целиком на PowerShell: изменения в подобных слабо-связанных модулях легко поддаются независимому тестированию и в конечном итоге не оказывают существенного влияния на стабильность всей системы. С MPS запросами всё оказалось гораздо сложнее. Поскольку они были основным интерфейсом взаимодействия контрольной панели и системы управления, их было действительно много и они пронизывали практически всё. Замена подобного куска функциональности на что-то другое было равносильно переписыванию значительной части всей системы с нуля, что могло пагубно сказаться либо на стабильности, либо на сроках выпуска продукта. К счастью мы использовали лишь ограниченный набор управляющих конструкций в запросах, формируемых контрольной панелью. В итоге было принято решение: на стороне нашей системы управления инфраструктурой реализовать частичную поддержку языка MPS`а, достаточную для обработки запросов контрольной панели в том виде, в котором они существовали на тот момент.

Реализованная поддержка языка MPS`а была действительно очень ограниченная, и скриптовые провайдеры были обречены. Но выбрасывать работающий код на компилируемом языке было бы большой глупостью, тем более что в случае провайдеров, написанных на языке C#, мы никогда не использовали MPS SDK напрямую. У нас была небольшая библиотека, которая полностью инкапсулировала все аспекты работы с MPS и таким образом изолировала провайдера от особенностей системы, в рамках которой ему предстояло функционировать. Поэтому, чтобы добиться полной совместимости нашей новой системой управления с нашими же провайдерами, написанными на языке C# для MPS`а, было достаточно просто переписать данную библиотеку.

Получившийся в итоге Windows Provisioning Engine представляет собой Web-сервис без состояния, реализующий единственный метод executeRequest. Запрос, который может быть передан этому методу на исполнение, формируется на урезанной версии языка MPS`а с возможностью использования лишь ограниченного набора управляющих конструкций. В качестве основных модулей расширения функциональности системы используются провайдеры, написанные на языке PowerShell. В дополнение к ним существует некоторое количество наших .NET провайдеров, перенесённых из MPS`а благодаря специальной библиотеке-прослойке. Отсутствие у Web-сервиса состояния позволяет решать задачу кластеризации системы управления без лишних затрат.

Продолжение следует...

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

Мурадов Мурад комментирует...

//обратите внимание на замечательный тэги foreach – вы никогда не видели цикла в XML – я прежде тоже
В XSLT же есть foreach http://www.w3schools.com/xsl/xsl_for_each.asp

Алексей Коротаев комментирует...

Ну от XSLT ты этого ожидаешь - суть у него такая. А тут именно декларация запроса в XML`е и вдруг управляющие конструкции вроде forEach, try, catch и прочего. Вообще там очень жуткая мешанина, которая местами включает даже XSLT. Но последнее весьма ограничено.

Но вообще спасибо за замечание - буду ещё внимательнее вычитывать текст в следующий раз.

Unknown комментирует...

Добрый день.
А продолжение будет?

Алексей Коротаев комментирует...

Извиняюсь, похоже забыл обновить ссылки на странице. Окончание серии вот здесь: http://mrnone.blogspot.ru/2012/11/powershell.html

Unknown комментирует...

Благодарю.

Отправить комментарий