Bug #1565

puppet parser not order independant

Added by Ryan McBride over 3 years ago. Updated 9 months ago.

Status:Accepted Start date:09/08/2008
Priority:Normal Due date:
Assignee:- % Done:

0%

Category:language
Target version:3.X
Affected Puppet version:0.22.1 Branch:
Keywords:
Votes: 0

Description

The puppet parser has number of issues regarding order-of evaluation:

  • It does not always ensure that included classes are evaluated before qualified variables referring to them are evaluated. (LanguageTutorial)
  • It may evaluate classes before the scope in which they are defined is evaluated.
  • the defined() function is “unfortunately dependent on the parse order of the configuration when testing whether a resource is defined.” (FunctionReference)

As far as I understand it, the intent is that puppet is a declarative language, in which order of evaluation should not matter, and it would be nice to have these issues cleared up. Conversely, if puppet continues to be “somewhat order dependant”, stronger mechanisms to provide control over order-of-execution or at least make order-of-execution more predictable are necessary. I believe the former is preferable.

The following example demonstrates the first two of these problems (tested on both 0.24.5 and HEAD):

######################################
# define some classes

class apache {
        apache_setup { "config" : }
}

define apache_setup (
        $chroot = true,
        $ssl = false
) {
        # sanity checking, platform-specific defaults
        $_chroot = $chroot
        $_ssl = $ssl

        class apache_config {
                $ssl = $_ssl
                $chroot = $_chroot
                # more variables here
        }
        include apache_config
        # actuall apache setup goes here
}

class trac {
        case $apache_config::chroot {
        true: {
                notice("chroot = true")
                # do something
        }
        default: {
                # do something else
                notice("chroot = ${apache_config::chroot}")
        }
        }
}


######################################
# Now use what we've set up

class apache_ssl inherits apache {
        # override the defaults
        Apache_setup["config"] {
                ssl => true,
                chroot => false
        }
}

include apache_ssl
#include apache_config
include trac

If this example is executed as-is, we recieve the error, it has clearly been included in apache_setup. (issue 1 above)

Class apache_config has not been evaluated so its variables cannot be referenced at /tmp/foo:26 on node 000AE43B1909

If we uncomment the ‘include apache_config’ directive at the bottom of the example to ensure that puppet sees the class as being included, puppet evaluates apache_config before the apache class and apache_setup define; the scope in which apache_config is defined is not evaluated, and the variables it depends on are evaluated as empty strings. (issue 2 above)

notice: Scope(Class[trac]): chroot =

History

Updated by Ryan McBride over 3 years ago

While I believe that these bugs are independent of what I’m actually trying to do in the example above, it may be helpful if I try to explain the intent:

I’d like to have a relatively generic and reliable mechanism to look into the configuration of one class/module from another. This is particularly useful with modules that have tight dependancy relationships; for example the many web applications which depend on apache. In some cases this may be used to drive configuration in the dependant module, other cases it may be used for sanity checking (eg: throw an error if Apache is configured to run chrooted and you’re installing a module which will not work in a chrooted environment).

In the example above, I’m trying to build the generically-named apache_config module, which can be referenced from other modules regardless of whether apache has been inherited on that specific node. The apache_setup define was an attempt to force puppet to evaluate apache_config in the correct order; this also provides the necessary inheritance support, and provides a nice way to override the module defaults in my site configuration: the standard “Apache_setup { ssl => true }”.

As mentioned on irc/#puppet, it is possible to provide the same behavior with node-scoped variables, something like:

class apache {
    $ssl = $apache_ssl {
       false => false,
       true => true,
       default = > false
    }
    $chroot = $apache_chroot {
       false => false,
       true => true,
       default = > true
    }
    # actual apache setup goes here
}

node "foo" {
    $apache_chroot = false
    $apache_ssl = true
    include apache
    include trac
}

However, this prevents me from using inheritance on the apache module (for example, to include additional files). I’d also prefer to be able to keep all of a module’s configuration in it’s own namespace, to keep things clean. Having the configuration via a define also allows me to force the user to provide a specific configuration value by not providing a default value in the define’s prototype.

Updated by James Turnbull over 3 years ago

  • Category set to language
  • Status changed from Unreviewed to Needs Decision
  • Assignee set to Luke Kanies
  • Target version set to 4

Updated by Ryan McBride over 3 years ago

DavidS pointed out on irc that the tagged() function is also order-dependent, as are variable definitions within a particular scope.

Updated by Luke Kanies about 2 years ago

  • Assignee changed from Luke Kanies to Markus Roberts
  • Target version changed from 4 to 2.7.x
  • Affected Puppet version set to 0.22.1

I think this will get solved by Markus’s ‘futures’ work.

Updated by James Turnbull about 1 year ago

  • Assignee changed from Markus Roberts to Nigel Kersten

Updated by Nigel Kersten 9 months ago

  • Status changed from Needs Decision to Accepted
  • Assignee deleted (Nigel Kersten)
  • Target version changed from 2.7.x to 3.X

Also available in: Atom PDF