Задача
Мы используем Opsview для мониторинга и Puppet для управления конфигурациями. В Opsview есть шаблоны (Host Templates), которые позволяют определить определенный список проверок (Service Checks) для определенного типа хостов. Например для хоста с шаблоном IIS будут проверяться всевозможные параметры IIS данного хоста, к примеру количество текущих подключений или например средняя скорость подключения.
Возникла задача автоматически назначать шаблон на хост, в зависимости от того, какие классы назначены в манифесте. Всё это, как всегда, для удовлетворения потребности автоматизации и лени. Итоговая цель — назначил хосту класс, вернулся через минут 15, а он уже с уствновленным IIS, с настроенными сайтами (как вариант уже с деплойнутым контентом), все они мониторятся и по этим данным строятся графики, а также алерты дают знать если что-то случилось.
Сложности
Основная сложность здесь, как обычно, в том что этого никто не сделал этого для меня. Не существует модуля «Мониторинг IIS в один клик» для моей инфраструктуры. Практически сложность заключается в том, как сообщить модулю который управляет конфигурацией Opsview что в другом модуле создали сайт, передать параметры URI которые нужно мониторить, а также имена шаблонов хоста (в данном случае это будет как минимум шаблон IIS). Мои попытки и пробы включали следующее:
Глобальные переменные
Не сработало, потому что у puppet scoping (как по-русски?) работает таким образом, что нельзя сделать append ко глобальной переменной, можно только сделать копию, а нам ведь нужно именно аккумулировать имена шаблонов, так как у нас может их быть бесчисленное множество.
Шаблоны Ruby
Также есть вариант реализации глобальных переменных через шаблоны (это когда в скобках < % пишем ruby код %>, который присваивает соответствующие значения, но это считается багом и может быть исправлено в следующих Версиях puppet (убрана фишка с возможностью установки значений переменных в других scope).
Plussignment
Бегло посмотрел возможности назначения параметров ресурса при помощи "~>" — вроде как значения склеивались, но все опять сводилось либо к глобальным переменным или к тому, что описывать весть хост который мы мониторим приходилось в каждом месте где мы хотим добавить шаблон к этому хосту, а это не совсем возможно, так как мы не всегда можем знать исходные параметры данного ресурса, а они обязательны — например имя хоста, которое формируется в основном классе opsview::node, и так далее).
Доработать Провайдер
Думал доделать провайдер управления Opsview, что может быть и стало верным решением при правильной реализации (здесь опять вероятные сложности с необходимостью декларации всегоо ресурса в каждом месте) и на ум пришло вот что (как всегда «слишком просто» для многих).
Реализация
Посколько среда гетерогенная (по-русски — «зоопарк»), нужно думать в масштабе, как минимум, Windows и Linux.
Windows
Оказывается если установить переменную окружения на требуемой ноде в виде FACTER_host_temates=IIS Server;Windows Server WMI;Basic Network то при следующем прогоне puppet run это превратится в факт, который можно будет использовать в любом манифесте как глобальную переменную, а это-то нам и надо! Я не стал писать отдельный провайдер, а быстренько создал новый тип, который использует прекрасный модуль windows_env. Все предельно просто, нужно только заметить что имя ресурса должно быть уникальным, поэтому приходится использовать дополнительный параметр (по умолчанию имя переменной среды берется из названия ресурса). В объявлении ресурса fact имеем возможность использовать имя ресурса для передачи имени переменной окружения. В качестве разделителя используется стандартное для Windows ";"
Linux
Второй частью задачи являлось выполнить тоже самое, но под Linux. Я знаю что управление переменными окружения в nix прямолинейно, и ничего сложного в оборачивании bash команд в ресурс puppet нет, я все же надеялся что кто-то сделал уже доброе дело и изобретать колесо не придется, но не тут то было… Пришлось сделать небольшие «костыли». Делаю я это создавая файл в дефолтном профиле, где экспортируется переменная окружения со всеми значениями (через двоеточие). Все это было разложено по правильным операционным системам и были добавлены проверки чтобы лишний раз ничего не запускалось.
define fact ($fact_name=$name, $value, $ensure = present) { case $::osfamily { 'windows': { windows_env { "${fact_name}:${value}": variable => "FACTER_${fact_name}", ensure => $ensure, mergemode => insert, value => $value, notify => Service['puppet'], #Restart service after environment update } } 'RedHat': { $splitvalue = join($value,":") file { "/etc/profile.d/FACTER_${fact_name}.sh": ensure => present, content => "export FACTER_${fact_name}=\"${$splitvalue}\"", mode => 775, } exec { "FACTER_${fact_name}=${splitvalue}": command => "/bin/bash -c \"source /etc/profile\"", unless => "/bin/echo \${FACTER_${fact_name}} | /bin/grep -q \"${splitvalue}\"", subscribe => File["/etc/profile.d/FACTER_${fact_name}.sh"], } } default: { case $::operatingsystem { 'Gentoo': { #No Gentoo in production. } } } } }
fact {"host_templates_iis_base": fact_name => "host_templates", value => ['Web Cluster','OS - Windows Server 2008 WMI - IIS Server'], ensure => present, }
#Устанавливаем разделитель в зависимости от операционной системы if $::kernel == "windows" { $delimeter=";" } else { $delimeter=":" } #Обращаемся к факту который содержит список шаблонов if $::host_templates { #Разбираем строку на элементы массива, если она содержит что-то $host_templates = split($::host_templates,$delimeter) } else { $host_templates =[] } #Здесь массив $host_templates уже либо null либо содержит список шаблонов. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Передаем информацию о хосте основному ресурсу opsview_monitored @@opsview_monitored { "$::hostname": ip => $ip, hosttemplates => $host_templates, hostattributes => $hostattributes, hostgroup => $hostgroup, enable_snmp => $enable_snmp, snmp_community => $snmp_community, snmp_port => $snmp_port, notification_interval => $notification_interval, servicechecks => $servicechecks, icon_name => $icon_name, keywords => $keywords, reload_opsview => "1", require => [Class['packages::opsview']], }
Заключение
Задача выполнена, данная реализация позволяет накапливать имена шаблонов в массиве, и применять их.
Недостатки: факты становятся доступны только на следующий запуск puppet, что при правильной обработке их (или их отсутствия) в основном классе opsview::node не является большой проблемой, т.к. данные параметры добавляются с низкой периодичностью (если вообще добавляются).
Достоинства: факты можно использовать не только для шаблонов opsview, но и для многих других задач, в том числе для добавления атрибутов, ключевых слов и любых других потенциально-кумулятивных параметров puppet. Факты Puppet можно устанавливать не только вручную, но и через код, что позволяет использовать их в качестве основы для многих интересных вещей.
Как всегда, данное решение хоть оно и полностью рабочее, не претендует на место самого «правильного», и если у кого-то есть какие-либо мысли по этому поводу — милости прошу в комменты. Часто приходится решать проблемы, решения для которых пока просто не существует, так недавно пришлось писать собственный провайдер для управления реестром Windows, так-как существующий puppetlabs/registry не хотел работать с ключами содержащими символ "\" в любых вариантах, с экранированием или без.
Если кому-то данный пост был интересен, буду рад еще поделиться опытом управления конфигурациями.
ссылка на оригинал статьи http://habrahabr.ru/post/203184/
Добавить комментарий