6 Puppet - 模板 & 类
1 模板
Templating是一种以标准格式获取内容的方法,可以在多个位置使用。
在 Puppet 中,使用 erb 支持模板和模板,erb 作为标准 Ruby 库的一部分,可用于除 Ruby 之外的其他项目,例如 Ruby on Rails 项目。
作为一种标准做法,需要对 Ruby 有基本的了解。当用户尝试管理模板文件的内容时,模板化非常有用。当无法通过内置 Puppet 类型管理配置时,模板起着关键作用。
评估模板
模板使用简单的函数进行评估。
$value = template ("testtemplate.erb")
可以指定模板的完整路径,也可以拉取 Puppet 的模板目录中的所有模板,模板目录通常位于 /var/puppet/templates
。
可以通过运行 puppet --configprint templatedir
找到目录位置。
模板总是由解析器而不是客户端评估,这意味着如果使用 puppetmasterd,那么模板只需要在服务器上,不需要将它们下载到客户端。
客户端如何看待使用模板和将文件的所有内容指定为字符串之间没有区别。这清楚地表明,puppetmasterd 在 puppet 启动阶段首先学习了特定于客户端的变量。
使用模板
以下是为测试站点生成 tomcat 配置的示例。
define testingsite($cgidir, $tracdir) {
file { "testing-$name":
path => "/etc/tomcat/testing/$name.conf",
owner => superuser,
group => superuser,
mode => 644,
require => File[tomcatconf],
content => template("testsite.erb"),
notify => Service[tomcat]
}
symlink { "testsym-$name":
path => "$cgidir/$name.cgi",
ensure => "/usr/share/test/cgi-bin/test.cgi"
}
}
以下是模板定义。
<Location "/cgi-bin/ <%= name %>.cgi">
SetEnv TEST_ENV "/export/svn/test/<%= name %>"
</Location>
# You need something like this to authenticate users
<Location "/cgi-bin/<%= name %>.cgi/login">
AuthType Basic
AuthName "Test"
AuthUserFile /etc/tomcat/auth/svn
Require valid-user
</Location>
这会将每个模板文件推送到一个单独的文件中,然后只需告诉 Apache 加载这些配置文件。
Include /etc/apache2/trac/[^.#]*
组合模板
使用以下命令可以轻松组合两个模板。
template('/path/to/template1','/path/to/template2')
模板中的迭代
Puppet 模板还支持数组迭代。如果 variable one
正在访问的变量是一个数组,那么可以对其进行迭代。
$values = [val1, val2, otherval]
我们可以有如下模板。
<% values.each do |val| -%>
Some stuff with <%= val %>
<% end -%>
上述命令将产生以下结果。
Some stuff with val1
Some stuff with val2
Some stuff with otherval
模板中的条件
erb 模板支持条件。以下构造是有条件地将内容放入文件中的一种快速简便的方法。
<% if broadcast != "NONE" %> broadcast <%= broadcast %> <% end %>
模板和变量
除了填写文件内容外,还可以使用模板填写变量。
testvariable = template('/var/puppet/template/testvar')
未定义的变量
如果需要在使用变量之前检查变量是否已定义,则可以使用以下命令。
<% if has_variable?("myvar") then %>
myvar has <%= myvar %> value
<% end %>
超出范围的变量
可以使用 lookupvar 函数显式查找超出范围的变量。
<%= scope.lookupvar('apache::user') %>
Sample Project Template
<#Autogenerated by puppet. Do not edit.
[default]
#Default priority (lower value means higher priority)
priority = <%= @priority %>
#Different types of backup. Will be done in the same order as specified here.
#Valid options: rdiff-backup, mysql, command
backups = <% if @backup_rdiff %>rdiff-backup,
<% end %><% if @backup_mysql %>mysql,
<% end %><% if @backup_command %>command<% end %>
<% if @backup_rdiff -%>
[rdiff-backup]
<% if @rdiff_global_exclude_file -%>
global-exclude-file = <%= @rdiff_global_exclude_file %>
<% end -%>
<% if @rdiff_user -%>
user = <%= @rdiff_user %>
<% end -%>
<% if @rdiff_path -%>
path = <%= @rdiff_path %>
<% end -%>
#Optional extra parameters for rdiff-backup
extra-parameters = <%= @rdiff_extra_parameters %>
#How long backups are going to be kept
keep = <%= @rdiff_keep %>
<% end -%>
<% if @backup_mysql -%>%= scope.lookupvar('apache::user') %>
[mysql]
#ssh user to connect for running the backup
sshuser = <%= @mysql_sshuser %>
#ssh private key to be used
sshkey = <%= @backup_home %>/<%= @mysql_sshkey %>
<% end -%>
<% if @backup_command -%>
[command]
#Run a specific command on the backup server after the backup has finished
command = <%= @command_to_execute %>
<% end -%>
Classes
Puppet 类被定义为资源的集合,这些资源被组合在一起以使目标节点或机器处于所需状态。这些类在位于 Puppet 模块内的 Puppet 清单文件中定义。使用类的主要目的是减少任何清单文件或任何其他 Puppet 代码中的相同代码重复。
以下是 Puppet 类的示例。
[root@puppetmaster manifests]# cat site.pp
class f3backup (
$backup_home = '/backup',
$backup_server = 'default',
$myname = $::fqdn,
$ensure = 'directory',
) {
include '::f3backup::common'
if ( $myname == '' or $myname == undef ) {
fail('myname must not be empty')
}
@@file { "${backup_home}/f3backup/${myname}":
# To support 'absent', though force will be needed
ensure => $ensure,
owner => 'backup',
group => 'backup',
mode => '0644',
tag => "f3backup-${backup_server}",
}
}
在上面的示例中,我们有两个用户需要存在的客户端。可以注意到,我们重复了两次相同的资源。在组合两个节点时不执行相同任务的一种方法。
[root@puppetmaster manifests]# cat site.pp
node 'Brcleprod001','Brcleprod002' {
user { 'vipin':
ensure => present,
uid => '101',
shell => '/bin/bash',
home => '/home/homer',
}
}
以这种方式合并节点来执行配置并不是一个好的做法。这可以通过创建一个类并将创建的类包含在节点中来简单地实现,如下所示。
class vipin_g01063908 {
user { 'g01063908':
ensure => present,
uid => '101',
shell => '/bin/bash',
home => '/home/g01063908',
}
}
node 'Brcleprod001' {
class {vipin_g01063908:}
}
node 'Brcleprod002' {
class {vipin_g01063908:}
}
需要注意的一点是类结构的外观以及我们如何使用 class 关键字添加新资源。 Puppet 中的每种语法都有自己的特点。因此,选择的语法取决于条件。
参数化类
和上面的例子一样,我们已经看到了如何创建一个类并将其包含在一个节点中。
现在有些情况下,我们需要在每个节点上进行不同的配置,例如需要在每个节点上使用相同的类有不同的用户。
此功能在 Puppet 中使用参数化类提供。新类的配置将如下例所示。
[root@puppetmaster ~]# cat /etc/puppet/manifests/site.pp
class user_account ($username){
user { $username:
ensure => present,
uid => '101',
shell => '/bin/bash',
home => "/home/$username",
}
}
node 'Brcleprod002' {
class { user_account:
username => "G01063908",
}
}
node 'Brcleprod002' {
class {user_account:
username => "G01063909",
}
}
当我们在节点上应用上述 site.pp 清单时,每个节点的输出将如下所示。
Brcleprod001
[root@puppetagent1 ~]# puppet agent --test
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppetagent1.testing.dyndns.org
Info: Applying configuration version '1419452655'
Notice: /Stage[main]/User_account/User[homer]/ensure: created
Notice: Finished catalog run in 0.15 seconds
[root@brcleprod001 ~]# cat /etc/passwd | grep "vipin"
G01063908:x:101:501::/home/G01063909:/bin/bash
Brcleprod002
[root@Brcleprod002 ~]# puppet agent --test
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppetagent2.testing.dyndns.org
Info: Applying configuration version '1419452725'
Notice: /Stage[main]/User_account/User[bart]/ensure: created
Notice: Finished catalog run in 0.19 seconds
[root@puppetagent2 ~]# cat /etc/passwd | grep "varsha"
G01063909:x:101:501::/home/G01063909:/bin/bash
还可以设置类参数的默认值,如下面的代码所示。
[root@puppetmaster ~]# cat /etc/puppet/manifests/site.pp
class user_account ($username = ‘g01063908'){
user { $username:
ensure => present,
uid => '101',
shell => '/bin/bash',
home => "/home/$username",
}
}
node 'Brcleprod001' {
class {user_account:}
}
node 'Brcleprod002' {
class {user_account:
username => "g01063909",
}
}