Many areas in the puppetlabs/apache module such as vhost.pp you can see error handling that requires the base class to be included first because the class in question uses the base class in its' parameter defaults.
Here in dev.pp there are no parameters though you can see the reference to $::apache::dev_packages
which is declared by the ::apache::params
class when ::apache
is initialized.
However, in vhosts.pp you can see that the base class is included explicitly without an expectation that it was previously included.
My understanding of this is that apache::vhosts
is designed to be used as a standalone class and it's inclusion of ::apache
initializes Apache's default configuration as determined by the module. However, if Apache is declared elsewhere such as:
class { '::apache':
*params*
}
Then the inclusion of the base class utilizes whatever values were passed as arguments to the base class. Is that correct? Why would two public classes apache::vhosts
and apache::dev
have two different requirements for usage?
Why would a Puppet module's main class be included by a sub-class?
First of all, these are not base and subclasses. Puppet does have class inheritance, but apache::dev
does not use it, and apache::vhost
isn't even a class (it's a defined type). The apache
class is the module's "main" class, and apache::dev
is simply another class in the same module.
Pretty much the only good use for class inheritance is to support obtaining class parameter defaults from another class's variables, but evidently, the people in control of Puppet's online docs no longer think that's a good idea either (though you can still see an example in class apache
). Hiera support for data in modules is a decent alternative, but I sometimes think that Puppet, Inc. is too fascinated with their shiny new goodies, and too dismissive of older features that work fine when used as documented, but break unfortunately when misused.
Here in dev.pp there are no parameters
... and no inclusion of class apache
. But there is code that will cause catalog building to fail in the event that apache
has not already been declared, separately.
However, in vhosts.pp you can see that the base class is included explicitly without an expectation that it was previously included.
Yes, that's fairly normal. More normal, indeed, than apache::dev
's behavior. apache::vhost
is intended for public use, so if you declare an instance then it ensures that everything it needs is included in the catalog, too.
My understanding of this is that
apache::vhosts
is designed to be used as a standalone class and it's inclusion of::apache
initializes Apache's default configuration as determined by the module.
Not exactly. apache::vhost
is intended to be a public type, and it does declare ::apache
to ensure that everything needed to support it is indeed managed. You can characterize that as "standalone" if you like. But the inclusion of ::apache
there is no different from the same anywhere else. If that class has already been added to the catalog then it it has no additional effect. Otherwise, it is added, with parameters drawn from Hiera data where such parameter data are defined, and hard-coded defaults where not. Hiera is how one should, generally, customize class parameters, and where that is done, the resulting apache configuration is not accurately characterized as "default" or defined by the module.
However, if Apache is declared elsewhere such as:
class { '::apache': *params* }
Then the inclusion of the base class utilizes whatever values were passed as arguments to the base class.
If such a resource-like class declaration has already been evaluated then, as I already said, apache::vhost
's include-like declaration has no additional effect. But if such a resource-like class declarations is evaluated later then catalog building will fail. This is one of the major reasons to avoid resource-like class declarations and rely on data binding via Hiera for class parameter customization.
Why would two public classes apache::vhosts and apache::dev have two different requirements for usage?
Because the module was developed over multiple years by hundreds of contributors. It is not surprising that that produced some inconsistency. Especially so because even Puppet developers who contribute to modules are at different points on the road to enlightenment.
The only plausible justification for preferring the approach of apache::dev
is to avoid interfering with a resource-like declaration of class apache
that is evaluated later, but avoiding such a failure by forcing a different failure is not a major gain. It does afford the opportunity to provide a clearer diagnostic in cases that would fail anyway, but at the expense of failing arbitrarily in other cases where it could just work instead.