使用 define 资源

Girl number twenty unable to define a horse!" said Mr. Gradgrind.?—?Charles Dickens.

— Hard Times

除非你知道如何定义你想要什么,不然不会得到预期的结果。 在上一节的示例中,我们看到了如何将同类资源组合成数组从而减少冗余代码。 然而,这种技术有一个限制,那就是所有的资源必须使用相同的参数。 当你有一组资源拥有一些公用的参数而其中一些资源确有不同的参数时, 就需要使用 define 资源将它们组合在一起。

操作步骤

  1. 在配置清单中添加如下代码:

    define tmpfile() {
        file { "/tmp/$name":
            content => "Hello, world",
        }
    }
    
    tmpfile { ["a", "b", "c"]: }
    
  2. 运行 Puppet:

    notice: /Stage[main]//Node[cookbook]/Tmpfile[a]/File[/tmp/a]/
    ensure: defined content as '{md5}bc6e6f16b8a077ef5fbc8d59d0b931b9'
    notice: /Stage[main]//Node[cookbook]/Tmpfile[b]/File[/tmp/b]/
    ensure: defined content as '{md5}bc6e6f16b8a077ef5fbc8d59d0b931b9'
    notice: /Stage[main]//Node[cookbook]/Tmpfile[c]/File[/tmp/c]/
    ensure: defined content as '{md5}bc6e6f16b8a077ef5fbc8d59d0b931b9'
    

工作原理

你可以认为 define 就像是一个饼干切割器。它描述了一种模式,Puppet 可以用它创建许多类似的资源。任何时候你都可以在你的配置清单中声明 tmpfile 实例,Puppet 将会插入包含在 tmpfile 定义中的所有资源。

在我们的例子中,名为 tmpfile 的 define 包含了一个 file 资源, 其 content 为 "Hello, world";其 path 为 "/tmp/$name"。 如果你用名字 foo 声明了一个 tmpfile 实例,如下所示:

tmpfile { "foo": }

会被 Puppet 要创建的实例名字所代替。这就像是我们创建了一个新的资源类型: tmpfile,它包含一个参数(即其名字)。

与常规资源一样,我们不仅可以为其传递一个字符串的名字,我们还可以传递一个数组名, Puppet 会对每一个数组元素创建一个 tmpfile 实例,就像上面的例子那样。

更多用法

在上面的例子中,我们定义的 define 仅有一个名字参数,不同实例的名字不同。 但是我们可以为其添加任何我们想要的参数,只要我们在 define 中声明这些参数即可:

define tmpfile( $greeting ) {
    file { "/tmp/$name":
        content => $greeting,
    }
}

当我们声明一个资源的实例时,可以为其传递参数值,例如:

tmpfile{ "foo": greeting => "Hello, world" }

你可以使用逗号间隔的列表同时声明多个参数:

define webapp( $domain, $path, $platform ) {
    ...
}

webapp { "mywizzoapp":
    domain   => "mywizzoapp.com",
    path     => "/var/www/apps/mywizzoapp",
    platform => "Rails",
}

这是对某些常见的资源进行抽象的一项强大的技术,抽象出资源之间的共性并保存在一个地方, 你就不必每次都做重复劳动Don’t Repeat Yourself)。 在上面的例子中,webapp 里或许有许多独立的资源:软件包(packages)、配置文件(config files)、 源码检出(source code checkouts)、虚拟主机(virtual hosts)等等, 但是除了我们为 webapp 提供的参数不同之外,所有实例要执行的工作都相同。 这些可能会在模板中引用,例如:为一个虚拟主机设置域名。