.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
?
答案1
因此,直接回答你的问题,我不相信获得出口资源清单直接地从 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" |>>
}
接下来,我们使用 .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 -%>
答案2
好吧,首先我放弃了,并将我的设置@@
为实际文件类型。好处是这仍然使用客户端主机上的变量。
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 主管软件本身允许我在 bacula-dir.conf 文件末尾执行以下操作:
@|"sh -c 'for f in /etc/bacula/conf.d/*.conf ; do echo @${f} ; done'"
因此,似乎仍然没有直接使用 ERB 模板来处理一组收集的资源的方法,但可以收集类型。这可以包括 Augeas 类型以将所有内容塞入一个文件中,或者将文件收集到配置中的 hack。但它还没有包括我在这个问题上寻找的内容。
答案3
我找到了一种使用 PuppetDB 服务的方法,这种方法对于这种情况非常有效,尽管有点不专业。要使用这种方法,您需要让 PuppetDB 正常运行(您应该已经拥有此功能,因为您正在使用导出的资源),并且需要从 puppetmaster(本地主机)获取 PuppetDB API。
然后,您需要将希望收集到数组中的所有资源导出到文件系统上的专用目录中。此目录路径将用于唯一标识目标资源。
然后,在您的模板中执行如下操作:
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 是上面提到的搜索路径,格式为 Ruby Regex,retVal 是完成的数组。这利用了模板在 puppetmaster 上处理,因此不需要特殊的 API 凭据。这还假设资源 namevar 是目标文件的完全限定路径,如果您有复杂的 namevar 并使用路径属性,则需要更复杂的逻辑。另请注意,这将返回所有资源,包括导出的和本地的。返回的数据有许多属性,如果需要,可以用于更复杂的逻辑。
虽然有点奇怪,但效果很好。