场景:我的configuration文件由一个.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 -%>
服务器的configuration文件需要为每个客户端主机重复input。 如果我要创build一个简单的数组,这将工作没有问题。 然而,我想要做的是让每个主机自己注册,然后使用<<| |>>收集数据 <<| |>>编译指示与nagios_*types的nagios_*相似。
这个标准的例子涉及导出一个types。
class ssh { @@sshkey { $hostname: type => dsa, key => $sshdsakey } Sshkey <<| |>> }
但是,我不能完全弄清楚如何编写一个types或引用它的方式,使我可以从.erb模板中读取数组的值。 有没有一种方法可以将导出的资源与.erb文件中的variables循环结合使用?
所以,要直接回答你的问题,我不相信直接从erb获取导出资源的列表是可能的。 这是由于出口资源的性质。 对于Puppet,它们只是需要在主机上创build的更多资源。
但是,有一种方法可以完成你想要做的事情。 我在我的环境中的一些地方做。
这里我们创build一个文件目录,每个主机我们要标记为“bacula_client”。 我们使用purge , force和recurse选项来删除不受Puppetpipe理的文件(例如,如果你想从这个“列表”中删除一个系统)。
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" |>> }
接下来,我们在.erb中使用一些Ruby代码来扫描该目录中的文件,并对其执行操作:
<% 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 -%>
那么,首先我放弃了,并在实际的文件types上设置我的@@ 。 好处是这仍然使用客户端主机上的variables。
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 } ... }
清除和recursion清除任何未定义的内容。 当我离线主机时, puppetstoredconfigclean $hostname会清除事实,导演的下一次puppet会相应地重置configuration。
最后,Bacula导向器软件本身允许我在我的bacula-dir.conf文件的末尾执行以下操作:
@|"sh -c 'for f in /etc/bacula/conf.d/*.conf ; do echo @${f} ; done'"
因此,似乎还没有一种直接的方式来使用ERB模板来收集一组资源,但是可以收集一个types。 这可以包括Augeastypes,将所有内容填充到一个文件中,或者将文件收集到configuration中。 尽pipe如此,这还不包括我在寻找的问题。
我已经find了一种使用PuppetDB服务的方法,这种方法对于这种情况非常有效,虽然有些骇人听闻。 要使用这个,你需要使PuppetDB可以运行(当你使用导出的资源时,你应该已经拥有了PuppetDB),并且PuppetDB API将需要从puppetmaster(localhost)中安静地运行。
然后,您将希望将您希望收集的所有资源导出到文件系统上的专用目录中。 此目录path将用于唯一标识目标资源。
然后,在你的模板中,做这样的事情:
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是服务器的FQDN,pathRegex是上面提到的searchpath,格式为Ruby Regex,retVal是完整的数组。 这利用了模板在puppetmaster上处理,所以不需要特殊的API凭证。 这也假定资源namevar是目标文件的全限定path,如果你有复杂的名字并且使用path属性,将需要更复杂的逻辑。 还要注意,这是返回所有资源,包括出口和本地。 返回的数据有许多属性,如果需要可以用于更复杂的逻辑。
有点哈克,但它运作良好。