Сценарий: мой файл конфигурации определяется .erb
файл, который включает приведенный ниже фрагмент.
<% backupclients.each do |backup_files| -%>
Job {
Name = "Server"
JobDefs = "DefaultJob"
Client = <%= backup_files %>-fd
Pool = TeraMonth
Write Bootstrap = "/var/lib/bacula/<%= backup_files %>.bsr"
}
<% end -%>
В файле конфигурации сервера требуется повторная запись для каждого клиентского хоста. Если бы я создал простой массив, это работало бы без проблем. Однако я хочу, чтобы каждый хост регистрировался сам, а затем собирал данные с помощью <<| |>>
прагма похожа на то, что можно было бы сделать с nagios_*
типы.
В стандартный пример для этого требуется экспорт типа.
class ssh {
@@sshkey { $hostname: type => dsa, key => $sshdsakey }
Sshkey <<| |>>
}
Однако я не могу понять, как написать тип или ссылаться на него таким образом, чтобы я мог читать этот массив значений из .erb
шаблон. Есть ли способ использовать экспортированные ресурсы в сочетании с циклом переменных в .erb
файл?
Итак, чтобы ответить прямо на ваш вопрос, я не верю, что получить список экспортированных ресурсов прямо от erb возможно. Это связано с природой экспортируемых ресурсов. Для Puppet это просто дополнительные ресурсы, которые необходимо создать на хосте.
Но есть способ выполнить то, что вы хотите сделать. Я делаю это в нескольких местах своего окружения.
Здесь мы создаем каталог файлов, по одному для каждого хоста, который мы хотим пометить как «bacula_client». Мы используем purge
, force
, и recurse
параметры для удаления файлов, которыми не управляет Puppet (т.е. если вы хотите удалить систему из этого «списка»).
class bacula::client {
@@file { "/etc/bacula_clients/$fqdn":
ensure => present,
content => "",
require => File['/etc/bacula_clients'],
tag => "bacula_client",
}
}
class bacula::server {
#
# .. include whatever else the server requires, like package {} file {} service {}
#
file { "/etc/bacula_clients":
ensure => directory,
purge => true,
recurse => true,
force => true,
}
# Populate directory of client files.
File <<| tag == "bacula_client" |>>
}
Затем мы используем некоторый код Ruby в .erb, чтобы сканировать этот каталог на наличие файлов и действовать с ними:
<%
bacula_clients_dir = '/etc/bacula_clients'
d = Dir.open(bacula_clients_dir)
# Remove directories from the list of entries in the directory (specifically '.' and '..'):
backupclients = d.entries.delete_if { |e| File.directory? "#{bacula_clients_dir}/#{e}" }
backupclients.each do |backup_files|
-%>
Job {
Name = "Server"
JobDefs = "DefaultJob"
Client = <%= backup_files %>-fd
Pool = TeraMonth
Write Bootstrap = "/var/lib/bacula/<%= backup_files %>.bsr"
}
<% end -%>
Ну, сначала я сдался и поставил @@
на фактическом типе файла. Положительным моментом является то, что при этом все еще используются переменные на клиентском хосте.
class bacula-client ($database = false) {
@@file { "${hostname}-bacula-client.conf":
mode => 600,
owner => bacula,
group => root,
path => "/etc/bacula/conf.d/${hostname}-client.conf",
content => template("bacula-dir-cliententry.erb"),
tag => 'bacula-client',
notify => Service[bacula-director]
}
...
}
Это позволяет мне использовать записи в файле erb, например:
<% if has_variable?("database") and database== "true" %>
...
<% end -%>
и объявления в моих файлах site.pp, например: class { bacula-client: database => "true" }
Чтобы обработать сам каталог:
class bacula-director {
file { '/etc/bacula/conf.d':
ensure => directory,
owner => bacula,
group => root,
mode => 600,
purge => true,
recurse => true
}
...
}
Очистка и рекурсия удаляют все, что не определено. Когда я отключаю хоста, puppetstoredconfigclean $hostname
очистит факты, и при следующем запуске марионетки на директоре произойдет соответствующий сброс конфигурации.
Наконец, сама программа Bacula Director позволяет мне делать следующее в конце моего файла bacula-dir.conf:
@|"sh -c 'for f in /etc/bacula/conf.d/*.conf ; do echo @${f} ; done'"
Таким образом, по-прежнему не существует прямого способа использования шаблона ERB для собранного набора ресурсов, но можно собрать типы. Это может включать типы Augeas, чтобы собрать все в один файл, или хитрость сбора файлов в конфигурацию. Однако в нем еще нет того, что я искал по этому вопросу.
Я нашел метод, использующий службу PuppetDB, который довольно хорошо работает в этой ситуации, хотя и немного хакерский. Чтобы использовать это, вам нужно, чтобы PuppetDB был в рабочем состоянии (который у вас уже должен быть, поскольку вы используете экспортированные ресурсы), а API PuppetDB должен быть управляемым от puppetmaster (localhost).
Затем вы захотите экспортировать все ресурсы, которые вы хотите собрать, в свой массив в специальный каталог файловой системы. Этот путь к каталогу будет использоваться для однозначной идентификации целевых ресурсов.
Затем в своем шаблоне сделайте что-то вроде этого:
require 'rest_client'
require 'json'
resources=JSON.parse(RestClient.get("http://localhost:8080/v2/nodes/#{nodename}/resources", {:accept => :json}))
retVal = Array.new
resources.each do |resource|
if resource["title"] =~ /^#{pathRegex}$/
retVal.push(resource["title"])
end
end
Где nodename - это полное доменное имя сервера, pathRegex - это путь поиска, упомянутый выше, в формате Ruby Regex, а retVal - это завершенный массив. При этом используется то, что шаблон обрабатывается на puppetmaster, поэтому специальные учетные данные API не требуются. Это также предполагает, что переменная имени ресурса - это полный путь к целевым файлам, если у вас есть сложные переменные имени и используется атрибут пути, потребуется более сложная логика. Также обратите внимание, что это возвращает все ресурсы, как экспортированные, так и локальные. Возвращенные данные имеют множество атрибутов, которые при необходимости можно использовать для более сложной логики.
Немного хакерский, но работает хорошо.