Назад | Перейти на главную страницу

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

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

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