On Monday, September 9, 2013 10:44:30 AM UTC-5, blalor wrote: > > As my previous email this morning probably indicated, I'm struggling with > the use of the defined( ) function. The > documentation<http://docs.puppetlabs.com/references/latest/function.html#defined> > says > its operation is parse-order dependent; I'm trying to figure out how it's > usable at all. >
It isn't. Do not use it. > Since resource order with Puppet is nondeterministic (without explicitly > using chaining arrows or before/after), > 'before', 'after', and chaining do not enter the picture. They affect only the order in which resources are applied to the target, but what you need to worry about is the order in which declarations are evaluated during catalog compilation. > how can I reliably test for the presence of a resource, like a package? > You should not test for the presence of a resource in the catalog. You can use a custom fact to test for the presence of a resource on the target system, or you can design your manifest set so that you know whether a particular resource is supposed to be declared (even if the declaration has not yet been evaluated), but you should avoid testing the current state of the catalog. Testing current catalog state during compilation is inherently evaluation-order dependent. > I see lots of instances of > > if ! defined(Package['some-package']) { … } > > Alas, the computing world is awash in poor code. Its prevalence should not be taken as an indication of quality. > in other peoples' code. Maybe I'm not understanding what's meant by > "parse order", however. Could someone explain? > > "Parse order" is actually a bit of a misnomer, of which I am as guilty as anybody. I'm trying to shift my personal usage to the term "evaluation order", though the difference is probably of little significance to most Puppet users. The particular example you present seems to be a relatively common anti-pattern. It attempts to address the problem that a particular class depends on a given package being present on the target system, but is uncertain whether that package is managed by another class. It wants to declare the class if it is not managed by someone else, therefore it uses defined() to test for a declaration already present in the catalog. That approach suffers from an insidious problem: it can subvert more specific, or even conflicting, declarations elsewhere in the manifest set without notification. Worse, it may flip back and forth between doing so and not as the manifest set changes. And that's not all. The approach works reliably (in that catalog compilation succeeds) only if *all*declarations of the resource are guarded the same way. If even one is not guarded, then whether catalog compilation succeeds or fails is evaluation-order dependent. One alternative is to provide a virtual declaration of the relevant resource in some central class that is reliably included in the catalog, and have those classes that need the resource realize it (or collect it) instead of declaring it themselves. Alternatively, a central class can provide a concrete declaration of the desired resource, and other classes that want the resource can 'include' the declaring class. The main objections to any of these approaches involve modularity and module compatibility. You would like to be able to use third-party modules without modifying them, and you would like your modules to avoid conflicting with each other. Additionally, you would prefer for your modules to be self-contained, or at least to be insensitive to declarations elsewhere in your manifest set. Unfortunately, *none* of the approaches above adequately address all those issues. This is a longstanding issue in Puppet, and although we have discussed possible approaches, no good solution has made it into the product yet. John -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscr...@googlegroups.com. To post to this group, send email to puppet-users@googlegroups.com. Visit this group at http://groups.google.com/group/puppet-users. For more options, visit https://groups.google.com/groups/opt_out.