Why would a Puppet module's main class be included by a sub-class?

Why would a Puppet module's main class be included by a sub-class?,puppet,puppetlabs-apache,Puppet,Puppetlabs Apache,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 i

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?


#1

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.


#2

Although this is an interesting question, it is also kind of moot because the params pattern exists from years ago when module data functionality did not exist, and you also generally should not be declaring class resources directly anymore by best practices. In modern best practices, you would use automatic parameter binding with module data (or environment or global), and then your parameter lookups would conform to that.

#3

@MattSchuchard I completely agree, I recognized this as the "legacy way" of handling module parameter data. It was more for curiosity's sake than anything. Thanks for pointing that out.

#4

Thank you, this really cleared things up for me. I appreciate the detailed response!