Привет всем.

В рамках данной заметки хотелось бы поделиться опытом использования кастомных, или как их еще называют внешних (external).

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

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

Ручное добавление фактов

Давайте представим такую ситуацию, что к нам пришла задача в которой требуется разбить хосты по группам - ServiceA и ServiceB. puppet-customs-vars01.png

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

Обновляем hiera.yaml

Идем в наше окружение, и обновляем файл hiera.yaml.

[root@puppetmaster ~]# cd /etc/puppetlabs/code/environments/production/
[root@puppetmaster production]# vim hiera.yaml
---
version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "Per-node data (yaml version)"
    path: "nodes/%{::trusted.certname}.yaml"
  - name: "Service data"
    path: "services/%{::service}.yaml"
  - name: "Other YAML hierarchy levels"
    paths:
      - "common.yaml"

В середину нашей иерархии мы добавили новый уровень:

  - name: "Service data"
    path: "services/%{::service}.yaml"

Данные для этого уровня будут расположены в каталоге ./data/services. У каждого сервиса будет свой одноименный файл данных.

Обновляем файлы окружения

Далее обновим файловую структуру на основании обновленного hiera.yaml. Сначада создаем каталог services, затем наклепаем yaml-файлики:

[root@puppetmaster production]# mkdir data/services
[root@puppetmaster production]# touch data/services/service-a.yaml
[root@puppetmaster production]# touch data/services/service-b.yaml

Продолжаем модулировать ситуацию, и теперь представим что на нашей условной инфраструктуре у хостов service-a должен в качестве беканда стоять postgresql, а у хостов service-b соответвенно должен стоять mysql. puppet-customs-vars02.png

В hiera файлах зафиксируем этот момент, указав значения переменной:

[root@puppetmaster production]# vim data/services/service-a.yaml
---
default_database: postgresql
[root@puppetmaster production]# vim data/services/service-b.yaml
---
default_database: mysql

Пишем манифест

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

[root@puppetmaster production]# mkdir modules/setup_database/manifests -p

Далее внутри нашего модуля инициирую новый класс именем - setup_database:

[root@puppetmaster production]# vim modules/setup_database/manifests/init.pp
---
class setup_database (
	String $database_package = lookup('default_database', default_value => 'mariadb'),
) {
	package {"$database_package-server":
		ensure => 'present',
	}

}

В атрибутах класса определяется единственная переменная $database_package, значение которой puppet найдет их данных hiera. Обратите внимание, что в вызове lookup() по мимо указания ключа, указываем значение которое будем использовать по умолчанию. То есть, если puppet не найдет значение по этому ключу, то будет использоваться указанное по умолчанию значение - mariadb.

Далее уже в теле класса следует один единственный ресурс - package, который просто установит пакет.

Проверить валидность манифеста можно командой:

[root@puppetmaster production]# /opt/puppetlabs/bin/puppet parser validate modules/setup_database/manifests/init.pp -v

Создаем кастомные факты

Для внешних фактов достаточно создать файлик в /opt/puppetlabs/facter/facts.d/, с содержимым в формате - key = value.

Например так:

[root@service-b ~]# echo "service=service-b" >> /opt/puppetlabs/facter/facts.d/facts.txt

Данный файлик создается на стороне хоста с агентом.

Далее что бы в проверочном формате получить значение, воспользуемся утилитой facter. В качестве аргумента передаем ключ от значения:

[root@service-b ~]# /opt/puppetlabs/bin/facter service
service-b

На второй ноде аналогичным способом создаем кастомный факт:

[root@service-a ~]# echo "service=service-a" > /opt/puppetlabs/facter/facts.d/facts.txt
[root@service-a ~]# /opt/puppetlabs/bin/facter service
service-a

Подключаем hiera и определяем класс

Для подключения hiera, в манифесте site.pp указываем импорт hiera-классов:

[root@puppetmaster production]# vim manifests/site.pp
---
hiera_include('classes')

Затем для всех хостов вешаем ранее созданный класс:

[root@puppetmaster production]# vim data/common.yaml
---
classes:
  - setup_database

Если все сделали правильно, то в течении 3x минут на хостах уже будут поставлены пакеты.

Подключамся в серверу - service-a.nixhub.ru, напомню там должен быть установлен postgresql, и проверяем:

[root@service-a ~]# rpm -q mysql
package mysql is not installed

[root@service-a ~]# rpm -q postgresql-server
postgresql-server-10.23-2.module_el8.8.0+3599+77865fc6.x86_64

Отлично изменения доставились. На втором сервере service-b.nixhub.ru должен был установится пакет с mysql. Аналогичным способом убеждаемся в этом:

[root@service-b ~]# rpm -q postgresql-server
package postgresql-server is not installed

[root@service-b ~]# rpm -q mysql-server
mysql-server-8.0.32-1.module_el8.8.0+3567+56a616e4.x86_64

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