Search code examples
puppet

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


In Puppet, it's possible to define a number of resources using an array of titles, like so:

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

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

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

I'm using puppet version 3.8.7, though I am curious if this behavior changes between Puppet 3 / 4 / 5.

I've searched the docs extensively, and while they do talk about defining resources with an array of titles, they don't talk about what order those resources get applied in.


Solution

  • This is kind of a complicated question to answer, but I will split up the question into components to help explain.

    Is this resource array ordering typical behavior in Puppet?

    Yes. To help with this, we need to delve into the Puppet DSL. Since arrays are part of the asymmetric syntax tree portion of the Puppet DSL (and usually for most if not all DSL), we need to check the relevant AST code of the Puppet Parser. The code for the commit at this time of writing is here. You can change the link to point at your version to see how and if the code has changed to see what the behavior will be for the version of Puppet you are using at any given time.

    The code we want to examine is:

    # 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
    

    So we see that the array of resources is iterated via the Array.map() method in Ruby. This converts the specific question component into "Does the Array.map() method in Ruby preserve ordering?". The specific type being iterated upon in the array is the title as specified in the type code when an instance is instantiated. This will typically be a symbol or a string, but the main point of emphasis here is that the iteration is over an array of simple types (i.e. not a nested hash etc.).

    The answer to this new question component is also yes as specified in the docs or a simple yes in this linked answer.

    Is this resource array ordering a documented supported behavior in Puppet?

    No. You can check the relevant documentation here or here and see an absence of any mention of this behavior. Also, a former colleague directly asked Puppet about this a few years ago and their high-level response was the same as what I have outlined here thus far.

    The code for the resource arrays in the AST can change at any time without warning in the documentation since this is unsupported behavior.

    Should I depend on this unsupported but seemingly always existent behavior?

    Your call. If this is for something like creating nested directories, then the automatic require code in Puppet will catch any issues with resources being applied out of order anyway. If not, then you probably need to do a quick cost/benefit calculation on code cleanliness versus potential undefined behavior, mitigated by a code lookup every time you upgrade, plus the time cost of said code lookup.