Меню

Master of puppets настройки



Как играть: Metallica — Master Of Puppets

Здесь я постараюсь описать, как играть одну из самых популярных песен группы Metallica — Master Of Puppets. Песня очень интересная, как и сложная, а также в ней есть много интересных моментов и гитарных трюков. Чтобы ее сыграть нам потребуются владение даунстроком, хаммером, пулом, бэндами, переменным штрихом и пикслайдом.

Начинается песня с мощных риффов, (1-46 такты) который играется с помощью даунстрока (то есть удары медиатором только вниз) и палм мьюта (глушение струн ладонью правой руки). Играть этот рифф сразу тяжело, так что сначала практикуйтесь в медленном темпе, а потом уже поднимайте скорость. Начиная с 47 такта идет первый куплет. Сложности тут составляют изменение размера такта, как, например, в 50, 54, 58 и т.д. Первый куплет тоже играется даунстроком. В 96, 97 и похожих тактах нужно применять глушение струн левой рукой. Начиная со 121 и по 196 такты повторяется то, что мы играли начале. С 198 такта начинается партия на чистом звуке. Особых сложностей она не представляет. С 208 такта начинается первое из двух гитарных соло. В нем используются приемы хаммер, пулл и гитарные бэнды (бэнды — это подтяжки струны, хаммер — ударение пальцем левой руки по ладу без звукоизвлечения, а пулл — сдергивание струны на определенном ладу). С 238 такта играется та же партия, что на чистом звуке, только уже на перегрузе и с хорошим глушением струн правой рукой. С 248 такта начинается рифф, перед соло. Он играется жестким даунстроком и завершается пикслайдом (ребром медиатора проведите по струнам, начиная от последнего лада). Соло играется с помощью таких гитарных приемов, как тремоло, пулл, бенды, и флажолеты. После гитарного соло идет рифф, который тоже играется даунстроком (конечно, как же без него :)) и переменный штрих. С 317 такта повторяем все, что играли ранее.

Вот и все! Надеюсь вам понравился разбор. Если есть какие пожелания или комментарии, пишите, не стесняйтесь!

Источник

Введение в Puppet

Категории

Свежие записи

Наши услуги

Puppet — это система управления конфигурацией. Он используется для приведения хостов к нужному состоянию и поддержания этого состояния.

Я работаю с Puppet уже больше пяти лет. Этот текст — по сути переведённая и переупорядоченная компиляция ключевых моментов из официальной документации, которая позволит новичкам быстро вникнуть в суть Puppet.

Базовая информация

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

Используется pull-модель работы: по умолчанию раз в полчаса клиенты обращаются к серверу за конфигурацией и применяют её. Если вы работали с Ansible, то там используется другая, push-модель: администратор инициирует процесс применения конфигурации, сами по себе клиенты ничего применять не будут.

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

Знакомство с манифестами

В терминологии Puppet к паппет-серверу подключаются ноды (nodes). Конфигурация для нод пишется в манифестах на специальном языке программирования — Puppet DSL.

Puppet DSL — декларативный язык. На нём описывается желаемое состояние ноды в виде объявления отдельных ресурсов, например:

  • Файл существует, и у него определённое содержимое.
  • Пакет установлен.
  • Сервис запущен.

Ресурсы могут быть взаимосвязаны:

  • Есть зависимости, они влияют на порядок применения ресурсов.
    Например, «сначала установи пакет, затем поправь конфигурационный файл, после этого запусти сервис».
  • Есть уведомления — если ресурс изменился, он отправляет уведомления подписанным на него ресурсам.
    Например, если изменяется конфигурационный файл, можно автоматически перезапускать сервис.

Кроме того, в Puppet DSL есть функции и переменные, а также условные операторы и селекторы. Также поддерживаются различные механизмы шаблонизации — EPP и ERB.

Puppet написан на Ruby, поэтому многие конструкции и термины взяты оттуда. Ruby позволяет расширять Puppet — дописывать сложную логику, новые типы ресурсов, функции.

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

Синтаксис и кодстайл

Вот разделы официальной документации, которые помогут разобраться с синтаксисом, если приведённых примеров будет недостаточно:

Вот пример того, как выглядит манифест:

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

  • Двухпробельные отступы, табы не используются.
  • Фигурные скобки отделяются пробелом, двоеточие пробелом не отделяется.
  • Запятые после каждого параметра, в том числе последнего. Каждый параметр — на отдельной строке. Исключение делается для случая без параметров и одного параметра: можно писать на одной строке и без запятой (т.е. resource < 'title': >и resource < 'title': param =>value > ).
  • Стрелки у параметров должны быть на одном уровне.
  • Стрелки взаимосвязи ресурсов пишутся перед ними.

Расположение файлов на паппетсервере

Для дальнейших объяснений я введу понятие «корневая директория». Корневая директория — это директория, в которой находится Puppet-конфигурация для конкретной ноды.

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

  • В третьей версии («старый Паппет») базовой директорией была /etc/puppet . Использование окружений опциональное — мы, например, их не используем со старым Паппетом. Если окружения используются, то они обычно хранятся в /etc/puppet/environments , корневой директорией будет директория окружения. Если окружения не используются, корневой директорией будет базовая.
  • Начиная с четвёртой версии («новый Паппет») использование окружений стало обязательным, а базовую директорию перенесли в /etc/puppetlabs/code . Соответственно, окружения хранятся в /etc/puppetlabs/code/environments , корневая директория — директория окружения.

В корневой директории должна быть поддиректория manifests , в которой лежит один или несколько манифестов с описанием нод. Кроме того, там должна быть поддиректория modules , в которой лежат модули. Что такое модули, я расскажу чуть позже. Кроме того, в старом Паппете также может быть поддиректория files , в которой лежат различные файлы, которые мы копируем на ноды. В новом Паппете же все файлы вынесены в модули.

Файлы манифестов имеют расширение .pp .

Пара боевых примеров

Описание ноды и ресурса на ней

На ноде server1.testdomain должен быть создан файл /etc/issue с содержимым Debian GNU/Linux n l . Файл должен принадлежать пользователю и группе root , права доступа должны быть 644 .

Взаимосвязи ресурсов на ноде

На ноде server2.testdomain должен быть запущен nginx, работающий с подготовленной заранее конфигурацией.

  • Нужно, чтобы был установлен пакет nginx .
  • Нужно, чтобы была скопированы конфигурационные файлы с сервера.
  • Нужно, чтобы был запущен сервис nginx .
  • В случае обновления конфигурации нужно перезапускать сервис.

Чтобы это работало, нужно примерно такое расположение файлов на паппет-сервере:

Типы ресурсов

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

Управляет файлами, директориями, симлинками, их содержимым, правами доступа.

  • название ресурса — путь к файлу (опционально)
  • path — путь к файлу (если он не задан в названии)
  • ensure — тип файла:
    • absent — удалить файл
    • present — должен быть файл любого типа (если файла нет — будет создан обычный файл)
    • file — обычный файл
    • directory — директория
    • link — симлинк
  • content — содержимое файла (подходит только для обычных файлов, нельзя использовать вместе с source или target)
  • source — ссылка на путь, из которого нужно копировать содержимое файла (нельзя использовать вместе с content или target). Может быть задана как в виде URI со схемой puppet: (тогда будут использованы файлы с паппет-сервера), так и со схемой http: (надеюсь, понятно, что будет в этом случае), и даже со схемой file: или в виде абсолютного пути без схемы (тогда будет использован файл с локальной ФС на ноде)
  • target — куда должен указывать симлинк (нельзя использовать вместе с content или source)
  • owner — пользователь, которому должен принадлежать файл
  • group — группа, которой должен принадлежать файл
  • mode — права на файл (в виде строки)
  • recurse — включает рекурсивную обработку директорий
  • purge — включает удаление файлов, которые не описаны в Puppet
  • force — включает удаление директорий, которые не описаны в Puppet
Читайте также:  Настройка обмена унф бухгалтерия

package

Устанавливает и удаляет пакеты. Умеет обрабатывать уведомления — переустанавливает пакет, если задан параметр reinstall_on_refresh.

  • название ресурса — название пакета (опционально)
  • name — название пакета (если не задано в названии)
  • provider — пакетный менеджер, который нужно использовать
  • ensure — желаемое состояние пакета:
    • present , installed — установлена любая версия
    • latest — установлена последняя версия
    • absent — удалён ( apt-get remove )
    • purged — удалён вместе с конфигурационными файлами ( apt-get purge )
    • held — версия пакета заблокирована ( apt-mark hold )
    • любая другая строка — установлена указанная версия
  • reinstall_on_refresh — если true , то при получении уведомления пакет будет переустановлен. Полезно для source-based дистрибутивов, где пересборка пакетов может быть необходима при изменении параметров сборки. По умолчанию false .

service

Управляет сервисами. Умеет обрабатывать уведомления — перезапускает сервис.

  • название ресурса — сервис, которым нужно управлять (опционально)
  • name — сервис, которым нужно управлять (если не задано в названии)
  • ensure — желаемое состояние сервиса:
    • running — запущен
    • stopped — остановлен
  • enable — управляет возможностью запуска сервиса:
    • true — включен автозапуск ( systemctl enable )
    • mask — замаскирован ( systemctl mask )
    • false — выключен автозапуск ( systemctl disable )
  • restart — команда для перезапуска сервиса
  • status — команда для проверки статуса сервиса
  • hasrestart — указать, поддерживает ли инитскрипт сервиса перезапуск. Если false и указан параметр restart — используется значение этого параметра. Если false и параметр restart не указан — сервис останавливается и запускается для перезапуска (но в systemd используется команда systemctl restart ).
  • hasstatus — указать, поддерживает ли инитскрипт сервиса команду status . Если false , то используется значение параметра status. По умолчанию true .

Запускает внешние команды. Если не указывать параметры creates, onlyif, unless или refreshonly, команда будет запускаться при каждом прогоне Паппета. Умеет обрабатывать уведомления — запускает команду.

  • название ресурса — команда, которую нужно выполнить (опционально)
  • command — команда, которую нужно выполнить (если она не задана в названии)
  • path — пути, в которых искать исполняемый файл
  • onlyif — если указанная в этом параметре команда завершилась с нулевым кодом возврата, основная команда будет выполнена
  • unless — если указанная в этом параметре команда завершилась с ненулевым кодом возврата, основная команда будет выполнена
  • creates — если указанный в этом параметре файл не существует, основная команда будет выполнена
  • refreshonly — если true , то команда будет запущена только в том случае, когда этот exec получает уведомление от других ресурсов
  • cwd — директория, из которой запускать команду
  • user — пользователь, от которого запускать команду
  • provider — с помощью чего запускать команду:
    • posix — просто создаётся дочерний процесс, обязательно указывать path
    • shell — команда запускается в шелле /bin/sh , можно не указывать path, можно использовать глоббинг, пайпы и прочие фичи шелла. Обычно определяется автоматически, если есть всякие спецсимволы ( | , ; , && , || и так далее).
  • название ресурса — просто какой-то идентификатор
  • ensure — состояние кронджоба:
    • present — создать, если не существует
    • absent — удалить, если существует
  • command — какую команду запускать
  • environment — в каком окружении запускать команду (список переменных окружения и их значений через = )
  • user — от какого пользователя запускать команду
  • minute, hour, weekday, month, monthday — когда запускать крон. Если какой-то из этих аттрибутов не указан, его значением в кронтабе будет * .

В Puppet 6.0 cron как бы удалили из коробки в puppetserver, поэтому нет документации на общем сайте. Но он есть в коробке в puppet-agent, поэтому ставить его отдельно не надо. Документацию по нему можно посмотреть в документации к пятой версии Паппета , либо на Гитхабе .

Про ресурсы в общем

Требования к уникальности ресурсов

Самая частая ошибка, с которой мы встречаемся — Duplicate declaration. Эта ошибка возникает, когда в каталог попадают два и более ресурса одинакового типа с одинаковым названием.

Поэтому ещё раз напишу: в манифестах для одной ноды не должно быть ресурсов одинакового типа с одинаковым названием (title)!

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

В других типах ресурсов есть аналогичные параметры, помогающие избежать дубликации, — name у service, command у exec, и так далее.

Метапараметры

Некоторые специальные параметры есть у каждого типа ресурса, независимо от его сущности.

Полный список метапараметров в документации Puppet .

  • require — в этом параметре указывается, от каких ресурсов зависит данный ресурс.
  • before — в этом параметре указывается, какие ресурсы зависят от данного ресурса.
  • subscribe — в этом параметре указывается, от каких ресурсов получает уведомления данный ресурс.
  • notify — в этом параметре указывается, какие ресурсы получают уведомления от данного ресурса.

Все перечисленные метапараметры принимают либо одну ссылку на ресурс, либо массив ссылок в квадратных скобках.

Ссылки на ресурсы

Ссылка на ресурс — это просто упоминание ресурса. Используются они в основном для указания зависимостей. Ссылка на несуществующий ресурс вызовет ошибку компиляции.

Синтаксис у ссылки следующий: тип ресурса с большой буквы (если в названии типа содержатся двойные двоеточия, то с большой буквы пишется каждая часть названия между двоеточиями), дальше в квадратных скобках название ресурса (регистр названия не меняется!). Пробелов быть не должно, квадратные скобки пишутся сразу после названия типа.

Зависимости и уведомления

Как уже было сказано ранее, простые зависимости между ресурсами транзитивны. Кстати, будьте внимательны при проставлении зависимостей — можно сделать циклические зависимости, что вызовет ошибку компиляции.

В отличие от зависимостей, уведомления не транзитивны. Для уведомлений действуют следующие правила:

  • Если ресурс получает уведомление, он обновляется. Действия при обновлении зависят от типа ресурса — exec запускает команду, service перезапускает сервис, package переустанавливает пакет. Если для ресурса не определено действие при обновлении, то ничего не происходит.
  • За один прогон Паппета ресурс обновляется не больше одного раза. Это возможно, так как уведомления включают в себя зависимости, а граф зависимостей не содержит циклов.
  • Если Паппет меняет состояние ресурса, то ресурс отправляет уведомления всем подписанным на него ресурсам.
  • Если ресурс обновляется, то он отправляет уведомления всем подписанным на него ресурсам.

Обработка неуказанных параметров

Как правило, если у какого-то параметра ресурса нет значения по умолчанию и этот параметр не указан в манифесте, то Паппет не будет менять это свойство у соответствующего ресурса на ноде. Например, если у ресурса типа file не указан параметр owner , то Паппет не будет менять владельца у соответствующего файла.

Знакомство с классами, переменными и дефайнами

Предположим, у нас несколько нод, на которых есть одинаковая часть конфигурации, но есть и различия — иначе мы могли бы описать это всё в одном блоке node <> . Конечно, можно просто скопировать одинаковые части конфигурации, но в общем случае это плохое решение — конфигурация разрастается, при изменении общей части конфигурации придётся править одно и то же во множестве мест. При этом легко ошибиться, ну и вообще принцип DRY (don’t repeat yourself) не просто так придумали.

Для решения такой проблемы есть такая конструкция, как класс.

Классы

Класс — это именованный блок паппет-кода. Классы нужны для переиспользования кода.

Сначала класс нужно описать. Само по себе описание не добавляет никуда никакие ресурсы. Класс описывается в манифестах:

Читайте также:  Настройка навигаторов во владивостоке

После этого класс можно использовать:

Пример из предыдущей задачи — вынесем установку и настройку nginx в класс:

Переменные

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

Внимание: переменные в Puppet неизменяемые!

Кроме того, обращаться к переменной можно только после того, как её объявили, иначе значением переменной окажется undef .

Пример работы с переменными:

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

Примеры пространства имён:

  • глобальное — туда попадают переменные вне описания класса или ноды;
  • пространство имён ноды в описании ноды;
  • пространство имён класса в описании класса.

Чтобы избежать неоднозначности при обращении к переменной, можно указывать пространство имён в имени переменной:

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

Однако приведённый пример плох тем, что есть некое «тайное знание» о том, что где-то внутри класса использует переменная с таким-то именем. Гораздо более правильно сделать это знание общим — у классов могут быть параметры.

Параметры класса — это переменные в пространстве имён класса, они задаются в заголовке класса и могут быть использованы как обычные переменные в теле класса. Значения параметров указывается при использовании класса в манифесте.

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

Давайте параметризуем класс из примера выше и добавим два параметра: первый, обязательный — путь к конфигурации, и второй, необязательный — название пакета с nginx (в Debian, например, есть пакеты nginx , nginx-light , nginx-full ).

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

Тип пишется непосредственно перед именем параметра:

Классы: include classname vs class

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

Если попробовать добавить класс на одну и ту же ноду два раза с помощью class < 'classname':>(без разницы, с разными или с одинаковыми параметрами), будет ошибка компиляции. Зато в случае использования класса в стиле ресурса можно тут же в манифесте явно задать все его параметры.

Однако если использовать include , то класс можно добавлять сколько угодно раз. Дело в том, что include — идемпотентная функция, которая проверяет, добавлен ли класс в каталог. Если класса в каталоге нет — добавляет его, а если уже есть, то ничего не делает. Но в случае использования include нельзя задать параметры класса во время объявления класса — все обязательные параметры должны быть заданы во внешнем источнике данных — Hiera или ENC. О них мы поговорим в следующей статье.

Дефайны

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

Например, для того, чтобы установить модуль PHP, мы в Авито делаем следующее:

  1. Устанавливаем пакет с этим модулем.
  2. Создаём конфигурационный файл для этого модуля.
  3. Создаём симлинк на конфиг для php-fpm.
  4. Создаём симлинк на конфиг для php cli.

В таких случаях используется такая конструкция, как дефайн (define, defined type, defined resource type). Дефайн похож на класс, но есть отличия: во-первых, каждый дефайн является типом ресурса, а не ресурсом; во-вторых, у каждого дефайна есть неявный параметр $title , куда попадает имя ресурса при его объявлении. Так же как и в случае с классами, дефайн сначала нужно описать, после этого его можно использовать.

Упрощённый пример с модулем для PHP:

В дефайне проще всего поймать ошибку Duplicate declaration. Это происходит, если в дефайне есть ресурс с константным именем, и на какой-то ноде два и более экземпляра этого дефайна.

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

Есть и другие способы достигнуть идемпотентности при добавлении ресурсов, а именно использование функций defined и ensure_resources , но про это расскажу в следующей серии.

Зависимости и уведомления для классов и дефайнов

Классы и дефайны добавляют следующие правила к обработке зависимостей и уведомлений:

  • зависимость от класса/дефайна добавляет зависимости от всех ресурсов класса/дефайна;
  • зависимость класса/дефайна добавляет зависимости всем ресурсам класса/дефайна;
  • уведомление класса/дефайна уведомляет все ресурсы класса/дефайна;
  • подписка на класс/дефайн подписывает на все ресурсы класса/дефайна.

Условные операторы и селекторы

unless

unless — это if наоборот: блок кода будет выполнен, если выражение ложно.

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

Селекторы

Селектор — это языковая конструкция, похожая на case , только вместо выполнения блока кода она возвращает значение.

Модули

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

Кроме того, есть проблема переиспользования кода — когда весь код в одном манифесте, сложно этим кодом делиться с другими. Для решения этих двух проблем в Puppet есть такая сущность, как модули.

Модули — это наборы классов, дефайнов и прочих Puppet-сущностей, вынесенных в отдельную директорию. Иными словами, модуль — это независимый кусок Puppet-логики. Например, может быть модуль для работы с nginx, и в нём будет то и только то, что нужно для работы с nginx, а может быть модуль для работы с PHP, и так далее.

Модули версионируются, также поддерживаются зависимости модулей друг от друга. Есть открытый репозиторий модулей — Puppet Forge .

На паппет-сервере модули лежат в поддиректории modules корневой директории. Внутри каждого модуля стандартная схема директорий — manifests, files, templates, lib и так далее.

Структура файлов в модуле

В корне модуля могут быть следующие директории с говорящими названиями:

  • manifests — в ней лежат манифесты
  • files — в ней лежат файлы
  • templates — в ней лежат шаблоны
  • lib — в ней лежит Ruby-код

Это не полный список директорий и файлов, но для этой статьи пока достаточно.

Названия ресурсов и имена файлов в модуле

Ресурсы (классы, дефайны) в модуле нельзя называть как угодно. Кроме того, есть прямое соответствие между названием ресурса и именем файла, в котором Puppet будет искать описание этого ресурса. Если нарушать правила именования, то Puppet просто не найдёт описание ресурсов, и получится ошибка компиляции.

Продемонстрирую на примере. Предположим, я пишу модуль nginx . В нём есть следующие ресурсы:

  • класс nginx описан в манифесте init.pp ;
  • класс nginx::service описан в манифесте service.pp ;
  • дефайн nginx::server описан в манифесте server.pp ;
  • дефайн nginx::server::location описан в манифесте server/location.pp .

Шаблоны

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

Как использовать шаблоны: значение шаблона можно раскрыть с помощью функции template , которой передаётся путь к шаблону. Для ресурсов типа file используем вместе с параметром content . Например, так:

Путь вида / подразумевает файл /modules/ /templates/ .

Кроме того, есть функция inline_template — ей на вход передаётся текст шаблона, а не имя файла.

Внутри шаблонов можно использовать все переменные Puppet в текущей области видимости.

Puppet поддерживает шаблоны в формате ERB и EPP:

Вкратце про ERB

  • — вставить значение выражения
  • — вычислить значение выражение (не вставляя его). Сюда обычный идут условные операторы (if), циклы (each).

Выражения в ERB пишутся на Ruby (собственно, ERB — это Embedded Ruby).

Для доступа к переменным из манифеста нужно дописать @ к имени переменной. Чтобы убрать перевод строки, появляющийся после управляющей конструкции, нужно использовать закрывающий тег -%> .

Пример использования шаблона

Предположим, я пишу модуль для управления ZooKeeper. Класс, отвечающий за создание конфига, выглядит примерно так:

А соответствующий ему шаблон zoo.cfg.erb — так:

Факты и встроенные переменные

Зачастую конкретная часть конфигурации зависит от того, что в данный момент происходит на ноде. Например, в зависимости от того, какой релиз Debian стоит, нужно установить ту или иную версию пакета. Можно следить за этим всем вручную, переписывая манифесты в случае изменения нод. Но это несерьёзный подход, автоматизация гораздо лучше.

Для получения информации о нодах в Puppet есть такой механизм, как факты. Факты — это информация о ноде, доступная в манифестах в виде обычных переменных в глобальном пространстве имён. Например, имя хоста, версия операционной системы, архитектура процессора, список пользователей, список сетевых интерфейсов и их адресов, и многое, многое другое. Факты доступны в манифестах и шаблонах как обычные переменные.

Пример работы с фактами:

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

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

Факты в виде исполняемых файлов

Такие факты кладутся в модули в директорию facts.d . Разумеется, файлы должны быть исполняемыми. При запуске они должны выводить на стандартный вывод информацию либо в формате YAML, либо в формате «ключ=значение».

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

Факты на Ruby

Такие факты кладутся в модули в директорию lib/facter .

Текстовые факты

Такие факты кладутся на ноды в директорию /etc/facter/facts.d в старом Паппете или /etc/puppetlabs/facts.d в новом Паппете.

Обращение к фактам

Обратиться к фактам можно двумя способами:

  • через словарь $facts : $facts[‘fqdn’] ;
  • используя имя факта как имя переменной: $fqdn .

Лучше всего использовать словарь $facts , а ещё лучше указывать глобальный неймспейс ( $::facts ).

Встроенные переменные

Кроме фактов, есть ещё некоторые переменные , доступные в глобальном пространстве имён.

  • trusted facts — переменные, которые берутся из сертификата клиента (так как сертификат обычно выпускается на паппет-сервере, агент не может просто так взять и поменять свой сертификат, поэтому переменные и «доверенные»): название сертификата, имя хоста и домена, расширения из сертификата.
  • server facts —переменные, относящиеся к информации о сервере — версия, имя, IP-адрес сервера, окружение.
  • agent facts — переменные, добавляемые непосредственно puppet-agent’ом, а не facter’ом — название сертификата, версия агента, версия паппета.
  • master variables — переменные паппетмастера (sic!). Там примерно то же самое, что в server facts, плюс доступны значения конфигурационных параметров.
  • compiler variables — переменные компилятора, которые различаются в каждой области видимости: имя текущего модуля и имя модуля, в котором было обращение к текущему объекту. Их можно использовать, например, чтобы проверять, что ваши приватные классы не используют напрямую из других модулей.

Дополнение 1: как это всё запускать и дебажить?

В статье было много примеров puppet-кода, но совсем не было рассказано, как же этот код запускать. Что ж, исправляюсь.

Для работы Puppet достаточно агента, но для большинства случаев нужен будет и сервер.

Агент

Как минимум с пятой версии пакеты puppet-agent из официального репозитория Puppetlabs содержат в себе все зависимости (ruby и соответствующие gem’ы), поэтому сложностей с установкой никаких нет (говорю про Debian-based дистрибутивы — RPM-based дистрибутивами мы не пользуемся).

В простейшем случае для применения puppet-конфигурации достаточно запустить агент в беcсерверном режиме: при условии, что puppet-код скопирован на ноду, запускаете puppet apply :

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

Можно имитировать push-модель работы — зайти на интересующую вас ноду и запустить sudo puppet agent -t . Ключ -t ( —test ) на самом деле включает несколько опций, которые можно включать и по отдельности. Среди этих опций следующие:

  • не работать в режиме демона (по умолчанию агент запускается в режиме демона);
  • завершить работу после применения каталога (по умолчанию агент продолжит работу и будет применять конфигурацию раз в полчаса);
  • писать подробный лог работы;
  • показывать изменения в файлах.

У агента есть режим работы без изменений — им можно пользоваться в случае, когда вы не уверены, что написали корректную конфигурацию, и хотите проверить, что именно поменяет агент во время работы. Включается этот режим параметром —noop в командной строке: sudo puppet agent -t —noop .

Кроме того, можно включить отладочный лог работы — в нём puppet пишет обо всех действиях, которые он производит: о ресурсе, который в данный момент обрабатывает, о параметрах этого ресурса, о том, какие программы запускает. Разумеется, это параметр —debug .

Сервер

Полноценную настройку паппетсервера и деплой на него кода в этой статье я не буду рассматривать, скажу лишь, что из коробки ставится вполне работоспособная версия сервера, не требующая дополнительной настройки для работы в условиях небольшого количества нод (скажем, до ста). Большее количество нод уже потребует тюнинга — по умолчанию puppetserver запускает не больше четырёх воркеров, для большей производительности нужно увеличить их число и не забыть увеличить лимиты памяти, иначе большую часть времени сервер будет garbage collect’ить.

Деплой кода — если нужно быстро и просто, то смотрите (на r10k)[ https://github.com/puppetlabs/r10k ], для небольших инсталляций его вполне должно хватить.

Дополнение 2: рекомендации по написанию кода

  1. Выносите всю логику в классы и дефайны.
  2. Держите классы и дефайны в модулях, а не в манифестах с описанием нод.
  3. Пользуйтесь фактами.
  4. Не делайте if’ов по хостнеймам.
  5. Не стесняйтесь добавлять параметры для классов и дефайнов — это лучше, чем неявная логика, спрятанная в теле класса/дефайна.

А почему я рекомендую так делать — объясню в следующей статье.

Заключение

На этом закончим со введением. В следующей статье расскажу про Hiera, ENC и PuppetDB.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите , пожалуйста.

На самом деле, материала гораздо больше — я могу написать статьи на следующие темы, проголосуйте, о чём вам интересно было бы почитать:

59,1%Advanced puppet constructs — some next-level shit: циклы, мэппинг и прочие лямбда-выражения, коллекторы ресурсов, экспортируемые ресурсы и межхостовое взаимодействие через Puppet, теги, провайдеры, абстрактные типы данных.13

31,8%«Я у мамки админ» или как мы в Авито подружили несколько паппет-серверов разных версий, ну и в принципе часть про администрирование паппет-сервера.7

81,8%Как мы пишем паппет-код: инструментальная обвязка, документация, тестирование, CI/CD.18

Проголосовали 22 пользователя. Воздержались 9 пользователей.

Источник

Adblock
detector