Puppet экспортировал ресурсы для переменных файла .erb?

8

Сценарий: мой файл конфигурации определяется .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файле?

Джефф Ферланд
источник
Они действительно должны оказаться в одном файле? Мне нравится, когда каждый хост находится в отдельном файле. Что-то вроде /etc/bacula/clientdefs/*.conf . С этим должно быть легче иметь дело.
Zoredache

Ответы:

5

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

Но есть способ выполнить то, что вы хотите сделать. Я делаю это в нескольких местах в моей среде.

Здесь мы создаем каталог файлов, по одному для каждого хоста, который мы хотим пометить как «bacula_client». Мы используем purge, forceи recurseопции для удаления файлов, которые не управляются с помощью кукол (то есть , если вы хотите , чтобы удалить систему из этого «списка»).

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 -%>
Кайл Смит
источник
Теперь я чувствую себя плохо, потому что я закончил писать свои сценарии два дня назад, и они очень близки по формату ... при этом я позволю вам выбрать, считаете ли вы свой ответ или мой ответ более подходящим для меня, чтобы принять.
Джефф Ферланд
Я бы сказал, что ваш ответ более уместен, если в приложении есть поддержка каталога конфигурации или подстановочный знак включения (как, кажется, bacula). Я использовал это в своей среде для сценариев, которые перемещают файлы на набор целевых хостов. Так что скрипты bash просто делают ls /path/to/flag/files|while read hostname; do ssh $hostname ..; done.
Кайл Смит
4

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

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очистлю факты, и следующий запуск puppet на директоре приведет к ошибочной перезагрузке конфигурации.

Наконец, программное обеспечение Bacula Director позволяет мне делать следующее в конце моего файла bacula-dir.conf:

@|"sh -c 'for f in /etc/bacula/conf.d/*.conf ; do echo @${f} ; done'"

Таким образом, пока еще нет прямого способа использовать шаблон ERB для сбора ресурсов, но можно собирать типы. Это может включать в себя типы Augeas, чтобы собрать все в один файл, или взломать сбор файлов в конфигурацию. Хотя это еще не включает то, что я искал по этому вопросу.

Джефф Ферланд
источник
1

Я наткнулся на метод, использующий сервис 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 не требуются. Это также предполагает, что ресурс namevar - это полный путь к целевым файлам, если у вас есть сложные namevars и вы используете атрибут path, потребуется более сложная логика. Также обратите внимание, что это возвращает все ресурсы, как экспортированные, так и локальные. Возвращенные данные имеют много атрибутов, которые при необходимости могут использоваться для более сложной логики.

Немного хакерский, но работает хорошо.

TJNII
источник