由一系列标题定义的资源是否总是按顺序评估?

Are resources defined by an array of titles always evaluated in order?

在 Puppet 中,可以使用标题数组定义大量资源,如下所示:

file { ['/some/file1', '/some/file2']:
  ensure => file,
}

关于申请的顺序,和下面的一样吗?

file { '/some/file1':
  ensure => file,
}
-> file { '/some/file2':
  ensure => file,
}

我使用的是 Puppet 版本 3.8.7,但我很好奇这种行为是否会在 Puppet 3 / 4 / 5 之间发生变化。

我广泛地搜索了文档,虽然他们确实讨论了用一系列标题定义资源,但他们没有讨论这些资源的应用顺序。

这是一个很难回答的问题,但我会将问题分解成几个部分来帮助解释。

此资源数组是否排序了 Puppet 中的典型行为?

是的。为了解决这个问题,我们需要深入研究 Puppet DSL。由于数组是 Puppet DSL 的非对称语法树部分的一部分(通常对于大多数(如果不是全部)DSL),我们需要检查 Puppet Parser 的相关 AST 代码。在撰写本文时提交的代码是 here。您可以将 link 更改为指向您的版本,以查看代码如何更改以及是否更改,以查看在任何给定时间您正在使用的 Puppet 版本的行为是什么。

我们要检查的代码是:

# Second level of implicit iteration; build a resource for each
# title.  This handles things like:
# file { ['/foo', '/bar']: owner => blah }
resource_titles.flatten.map do |resource_title| # <-- line of iterator
  exceptwrap :type => Puppet::ParseError do
    ...

    if resource.resource_type.is_a? Puppet::Resource::Type
      resource.resource_type.instantiate_resource(scope, resource)
    end
    scope.compiler.add_resource(scope, resource)
    scope.compiler.evaluate_classes([resource_title], scope, false) if fully_qualified_type == 'class'
    resource
  end
end

所以我们看到资源数组是通过Ruby中的Array.map()方法迭代的。这会将特定问题组件转换为 "Does the Array.map() method in Ruby preserve ordering?"。数组中迭代的特定类型是实例化时类型代码中指定的标题。这通常是一个符号或一个字符串,但这里的重点是迭代是在一个简单类型的数组上进行的(即不是嵌套哈希等)。

这个新问题的答案也是 docs or a simple yes in this linked answer 中指定的是。

此资源数组是否排序了 Puppet 中记录的受支持行为?

没有。您可以查看相关文档 here or here 并发现没有提及此行为。此外,一位前同事在几年前就此问题直接询问了 Puppet,他们的 high-level 回复与我到目前为止所概述的相同。

AST 中资源数组的代码可以随时更改,而不会在文档中发出警告,因为这是不受支持的行为。

我应该依赖这种不受支持但似乎一直存在的行为吗?

你来电。如果这是为了创建嵌套目录之类的东西,那么 Puppet 中的自动 require 代码将捕捉到资源被乱序应用的任何问题。如果不是,那么您可能需要快速 cost/benefit 计算代码清洁度与潜在的未定义行为,每次升级时通过代码查找来减轻,加上所述代码查找的时间成本。

In terms of order of application, is it the same as the following?

file { '/some/file1':
  ensure => file,
}
-> file { '/some/file2':
  ensure => file,
}

与另一个答案NO的说法相反,两者是not相等的。其他答案也没有不同的表现。它显示的是,在 Puppet 当前的实现中,您的 array-style 声明等同于:

file { '/some/file1':
  ensure => file,
}

# no chain operator here

file { '/some/file2':
  ensure => file,
}

由于您特别询问了应用程序的顺序,声明的资源之间没有任何明确的关系很重要。

现在,默认,在两个资源之间没有显式关系链的情况下,它们的相对应用顺序将与它们在清单中的相对求值顺序相同放。但这里有两个重要的警告:

  • 这只是默认设置。可以通过 Puppet's 'ordering' setting 更改默认 order-of-application 规则。如果是,则不能依赖您的 array-based 资源声明来生成与使用链运算符的替代方案相同的应用程序顺序。

  • 默认规则创建的隐式关系可以被显式规则覆盖或规避。如果在您的清单集中声明了一个或多个显式关系的相反链,那么 Puppet 将接受并使用 array-based 声明来接受它,但在显式链运算符之间的情况下,将拒绝它作为循环依赖资源声明。

如果应用程序的相对顺序很重要,则必须声明明确的关系。 Array-titled 资源声明没有这样的语义,但通常您可以单独添加关系并仍然获得数组标题的代码清晰和简洁的优势:

file { ['/some/file1', '/some/file2']:
  ensure => file,
}

File['/some/file1'] -> File['/some/file2']

上面有两个有趣的答案是不同意的。我将在这里添加我的 2 美分,并提供一些 OP 可能感兴趣的更多信息。

OP 已询问 一般 如果按照申请顺序:

file { ['/some/file1', '/some/file2']:
  ensure => file,
}

相当于:

file { '/some/file1':
  ensure => file,
}
-> file { '/some/file2':
  ensure => file,
}

一般来说,答案是 "no",正如约翰所说。

这里有一个简单的演示来证明:

傀儡版:

$ bundle exec puppet -V
5.3.3

我的代码:

# code.pp
include stdlib
$files = range(1, 10).map |$x| { "/tmp/file${x}" }
notice("Files array is: $files")
file { $files:
  ensure =>  file,
}

申请 --ordering=random:

$ bundle exec puppet apply --ordering=random code.pp 
Notice: Scope(Class[main]): Files array is: [/tmp/file1, /tmp/file2, /tmp/file3, /tmp/file4, /tmp/file5, /tmp/file6, /tmp/file7, /tmp/file8, /tmp/file9, /tmp/file10]
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.05 seconds
Notice: /Stage[main]/Main/File[/tmp/file3]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file9]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file8]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file7]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file6]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file4]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file10]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file5]/ensure: created
Notice: Applied catalog in 0.06 seconds

因此,如果没有明确的关系声明,Puppet 的随机排序设置会看到资源随机排序。但是,如果我们在清单中声明了明确的顺序:

# code.pp
file { '/tmp/file1':
  ensure => file,
}
-> file { '/tmp/file2':
  ensure => file,
}

文件总是按我们希望的顺序排列:

$ for i in {1..5} ; do rm -f /tmp/file* ; bundle exec puppet apply --ordering=random code.pp ; done
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.21 seconds
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: Finished catalog run in 0.02 seconds
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.20 seconds
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: Finished catalog run in 0.02 seconds
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.23 seconds
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: Finished catalog run in 0.02 seconds
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.22 seconds
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: Finished catalog run in 0.02 seconds
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.23 seconds
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: Finished catalog run in 0.02 seconds

我们还可以使用 Puppet 之前的默认 title-hash 排序获得 pseudo-random 排序,其中资源按从资源标题生成的哈希排序:

$ bundle exec puppet apply --ordering=title-hash code.pp 
Notice: Scope(Class[main]): Files array is: [/tmp/file1, /tmp/file2, /tmp/file3, /tmp/file4, /tmp/file5, /tmp/file6, /tmp/file7, /tmp/file8, /tmp/file9, /tmp/file10]
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.05 seconds
Notice: /Stage[main]/Main/File[/tmp/file3]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file6]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file8]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file4]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file7]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file10]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file5]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file9]/ensure: created
Notice: Applied catalog in 0.06 seconds

但是如果我们切换到清单排序,我们将再次按数字排序文件:

$ bundle exec puppet apply --ordering=manifest code.pp 
Notice: Scope(Class[main]): Files array is: [/tmp/file1, /tmp/file2, /tmp/file3, /tmp/file4, /tmp/file5, /tmp/file6, /tmp/file7, /tmp/file8, /tmp/file9, /tmp/file10]
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.05 seconds
Notice: /Stage[main]/Main/File[/tmp/file1]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file2]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file3]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file4]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file5]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file6]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file7]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file8]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file9]/ensure: created
Notice: /Stage[main]/Main/File[/tmp/file10]/ensure: created
Notice: Applied catalog in 0.07 seconds

我认为正如 John 所说,Matt 的回答是正确的,但只是假设使用 "manifest" 的默认排序;并假设 none 的资源 auto-require 其他资源。

另请参阅 Gary Larizza 关于订购的 post here