在使用 Puppet 时,我发现自己想要自动化更复杂的设置,例如 X 个网站的虚拟主机。随着我的 Puppet 清单变得越来越复杂,我发现很难应用 DRY(不要重复自己)原则。下面是我想要的简化片段,但它不起作用,因为 Puppet 会根据我使用类还是定义而抛出各种错误。我想从一些经验丰富的 Puppet 大师那里得到一些反馈,了解他们如何实现这个解决方案。
# site.pp
import 'nodes'
# nodes.pp
node nodes_dev {
$service_env = 'dev'
}
node nodes_prod {
$service_env = 'prod'
}
import 'nodes/dev'
import 'nodes/prod'
# nodes/dev.pp
node 'service1.ownij.lan' inherits nodes_dev {
httpd::vhost::package::site { 'foo': }
httpd::vhost::package::site { 'bar': }
}
# modules/vhost/package.pp
class httpd::vhost::package {
class manage($port) {
# More complex stuff goes here like ensuring that conf paths and uris exist
# As well as log files, which is I why I want to do the work once and use many
notify { $service_env: }
notify { $port: }
}
define site {
case $name {
'foo': {
class 'httpd::vhost::package::manage':
port => 20000
}
}
'bar': {
class 'httpd::vhost::package::manage':
port => 20001
}
}
}
}
}
该代码片段给了我一个Duplicate declaration: Class[Httpd::Vhost::Package::Manage]
错误,如果我将manage
类切换为定义,并尝试访问全局变量或传入 foo 和 bar 共同的变量,我就会收到错误Duplicate declaration: Notify[dev]
。
有什么建议可以让我实施 DRY 原则并且让 Puppet 正常工作?
- 更新 -
我仍然无法确保我的一些虚拟主机(可能共享父目录)设置正确。如下所示:
node 'service1.ownij.lan' inherits nodes_dev {
httpd::vhost::package::site { 'foo_sitea': }
httpd::vhost::package::site { 'foo_siteb': }
httpd::vhost::package::site { 'bar': }
}
我需要的是 sitea 和 siteb 有相同的父“foo”文件夹。我遇到的问题是当我调用定义以确保“foo”文件夹存在时。下面是我拥有的站点定义,希望它能理解我想要实现的目标。
class httpd::vhost::package {
File {
owner => root,
group => root,
mode => 0660
}
define site() {
$app_parts = split($name, '[_]')
$app_primary = $app_parts[0]
if ($app_parts[1] == '') {
$tpl_path_partial_app = "${app_primary}"
$app_sub = ''
} else {
$tpl_path_partial_app = "${app_primary}/${app_parts[1]}"
$app_sub = $app_parts[1]
}
include httpd::vhost::log::base
httpd::vhost::log::app { $name:
app_primary => $app_primary,
app_sub => $app_sub
}
}
}
class httpd::vhost::log {
class base {
$paths = [ '/tmp', '/tmp/var', '/tmp/var/log', '/tmp/var/log/httpd', "/tmp/var/log/httpd/${service_env}" ]
file { $paths:
ensure => directory
}
}
define app($app_primary, $app_sub) {
$paths = [ "/tmp/var/log/httpd/${service_env}/${app_primary}", "/tmp/var/log/httpd/${service_env}/${app_primary}/${app_sub}" ]
file { $paths:
ensure => directory
}
}
}
运行include httpd::vhost::log::base
良好,因为它是“包含的”,这意味着它只实现一次,即使site
被调用多次。我得到的错误是:Duplicate declaration: File[/tmp/var/log/httpd/dev/foo]
。我研究过使用exec
,但不确定这是正确的路线,肯定其他人以前也处理过这个问题,任何见解都会受到赞赏,因为我已经为此努力了几个星期。谢谢。
答案1
首先 - 您绝对应该使用define
for httpd::vhost::package::manage
,而不是class
,因为它将为同一个节点定义多次。
notify { $service_env: }
总是会搞砸,因为的两次调用$service_env
都是。您永远不能用相同的名称再次声明相同的资源。dev
define
您可以通过更改为类似的内容来解决这个问题notify { "${service_env}-${port}": }
,但如果它没有正确构建以处理设置为定义类型,您可能会遇到其他问题。
整个班级结构都很httpd::vhost::package::manage
奇怪 - 我建议真正将事情精简为一个班级结构,这将简化事情并允许您只拥有所需的资源。
httpd (init.pp - have it include the install, config, service classes)
httpd::install (install.pp - have it define Package[httpd] to install)
httpd::service (service.pp - have it define Service[httpd]; the vhost defines can
notify this to update)
httpd::config (config.pp - any configuration, such as handling of httpd.conf,
that won't be per-vhost)
httpd::vhost (vhost.pp - the defined type that can be used multiple times. Have
it include httpd so that the base classes are handled, and
notify httpd::service from your vhost config file resources)
vhost 管理的一个简单例子实际上是文档中定义类型的示例- 如果您需要任何其他说明如何将其设置为可重复使用的配置,请告诉我!
编辑:
更新共享父目录的问题。
在 Puppet 中管理来自两个不同位置的文件是一件很麻烦的事,以前也给我带来过麻烦。当两个资源声明之间没有冲突(如您当前的难题)时,尤其令人沮丧。
您说得对,exec
资源很可能就是您最好的答案。
define app($app_primary, $app_sub) {
exec { "mkdir_${service_env}_${app_primary}_${app_sub}":
command => "/bin/mkdir -p /tmp/var/log/httpd/${service_env}/${app_primary}/${app_sub}",
creates => "/tmp/var/log/httpd/${service_env}/${app_primary}/${app_sub}",
require => Class["httpd::vhost::log::base"],
}
}
这适用于两种情况(有和没有子目录),因为$app_sub
如果没有使用,则将其设置为空字符串。
我认为不共享目录树(用作log/httpd/foo_sitea
日志目录而不是log/httpd/foo/sitea
)可能更简洁,但这应该可以解决问题。拆分字符串并基于此进行不同的行为,以及所有这些单独的define
s,而这实际上可以存在于site
类中。确保保持简单!