Puppet: Declaring a class with inheritance - puppet

I currently have two classes that I created within /etc/puppet/modules/params/manifests/init.pp
class modulename ($variable_name = 'Any string') inherits modulename::params{
file { '/tmp/mytoplevelclass.sh' :
mode => '644',
ensure => 'present',
content => $variable_name
}
}
class modulename::params{
}
However, I am having an issue declaring these classes in /etc/puppet/manifests/site.pp. Currently, I have it written as
node default { #client
class { 'modulename':}
class { 'modulename::params':}
}
I know that this is incorrect because when I run puppet agent -t on the client I get an error stating
Could not find declared class modulename at /etc/puppet/manifests/site.pp
I have tried several different configurations and still am unsure on what to do.

Puppet determines the file in which it expects to find a class's definition based on the class's fully-qualified name. The docs go into it in some detail; in particular, you should review the Module Fundamentals. (I am guessing that you are on Puppet 3, but the details I am about to discuss are unchanged in Puppet 4.)
Supposing that /etc/puppet/modules is a directory in your modulepath, it is a fine place to install (or write) your modulename module, as indeed you indicate you are doing. If it is not in your module path, then you'll want either to move your module to a directory in the module path, or to add that directory to the module path. I assume that you will resolve any problem of this sort via the latter alternative, so that /etc/puppet/modules/modulename is a valid module directory.
Now, class 'modulename' is a bit special in that its name is also a module name; as such, it should be defined in /etc/puppet/modules/modulename/manifests/init.pp. Class modulename::params, on the other hand, should follow the normal pattern, being defined in /etc/puppet/modules/modulename/manifests/params.pp. I anticipate that Puppet will find the definitions if you put the definitions in the correct files.
Bonus advice:
Use include-like class declarations in your node blocks, not resource-like declarations
Your node blocks probably should not declare modulename::params at all

Related

Puppet: Class Ordering / Containment - always wrong order

I read a lot about ordering puppet classes with containment (iam using Puppet 6). But it still does not work for me in one case. Maybe my english is not good enough and i miss something. Maybe somebody know what iam doing wrong.
I have a profile to installing a puppetserver (profile::puppetserver). This profile has three sub-classes which I contain within the profile::puppetserver
class profile::puppetserver(
) {
contain profile::puppetserver::install
contain profile::puppetserver::config
contain profile::puppetserver::firewall
}
That works fine for me. Now I want to expand this profile and install PuppetDB. For this, i use the puppetdb module from puppet forge:
So what i do is add profile::puppetserver::puppetdb and the contain to the profile::puppetserver
class profile::puppetserver::puppetdb(
) {
# Configure puppetdb and its underlying database
class { 'puppetdb': }
# Configure the Puppet master to use puppetdb
class { 'puppetdb::master::config': }
}
When i provision my puppetserver first and add the profile::puppetserver::puppetdb after it, puppetdb installs and everything works fine.
If I add it directly with contain, and provisioning everything at once, it crashes. It's because the puppetdb module is installed randomly during my master server installs (and also the postgresql server and so on). That ends in my puppetserver is not running and my puppetdb generate no local ssl certificates and the service doesn't comes up.
What i try first:
I installed the puppetdb Package in my profile::puppetserver::puppetdb directly and use the required flag. It works when i provision all at once.
class profile::puppetserver::puppetdb (
) {
Package { 'puppetdb':
ensure => installed,
require => Class['profile::puppetserver::config']
}
}
So i think i could do the same in the code above:
class profile::puppetserver::puppetdb(
) {
# Configure puppetdb and its underlying database
class { 'puppetdb':
require => Class['profile::puppetserver::config']
}
# Configure the Puppet master to use puppetdb
class { 'puppetdb::master::config':
require => Class['profile::puppetserver::config']
}
}
But this does not work...
So i read about puppet class containment and ordering by chains. So i did this in my profile::puppetserver
class profile::puppetserver(
) {
contain profile::puppetserver::install
contain profile::puppetserver::config
contain profile::puppetserver::firewall
contain profile::puppetserver::puppetdb
Class['profile::puppetserver::install'] ->
Class['profile::puppetserver::config'] ->
Class['profile::puppetserver::firewall'] ->
Class['profile::puppetserver::puppetdb']
}
But it still does not have any effect... he still starts to install postgresql and the puppetdb package during my "puppetserver provisioning" in the install, config, firewall steps.
How i must write the ordering, that all things from the puppetdb module, which i call in profile::puppetserver::puppetdb, only starts when the rest of the provisioning steps are finished?
I really don't understand it. I think maybe it haves something to do with the fact, that i declare classes from the puppetdb module inside of profile::puppetserver::puppetdb and not the directly Resource Type. Because when i use the Package Resource Type with the Require Flag, it seems to work. But i really don't know how to handle this. I think there must be a way or?
I think maybe it haves something to do with the fact, that i declare
classes from the puppetdb module inside of
profile::puppetserver::puppetdb and not the directly Resource Type.
Because when i use the Package Resource Type with the Require Flag, it
seems to work.
Exactly so.
Resources are ordered with the class or defined-type instance that directly declares them, as well as according to ordering parameters and instructions applying to them directly.
Because classes can be declared multiple times, in different places, ordering is more complicated for them. Resource-like class declarations such as you demonstrate (and which you really ought to avoid as much as possible) do not imply any particular ordering of the declared class. Neither do declarations via the include function.
Class declarations via the require function place a single-ended ordering constraint on the declared class relative to the declaring class or defined type, and declarations via the contain function place a double-ended ordering constraint similar to that applying to all resource declarations. The chaining arrows and ordering metaparameters can place additional ordering constraints on classes.
But i really dont know how to handle this. I think there must be a way or?
Your last example shows a viable way to enforce ordering at the level of profile::puppetserver, but its effectiveness is contingent on each of its contained classes taking the same approach for any classes they themselves declare, at least where those third-level classes must be constrained by the order of the second-level classes. This appears to be where you are falling down.
Note also that although there is definitely a need to order some things relative to some others, it is not necessary or much useful to try to enforce an explicit total order over all resources. Work with the lightest hand possible, placing only those ordering constraints that serve a good purpose.

In puppet, how to retrieve variables inside a class scope from a different parameterized class

In the scope of one class, I need to be able to access a variable from another class. The variable is passed as a parameter, e.g.
class parameterized_class (
$param1,
) {
...
}
and
class other_class () {
include parameterized_class
Class['parameterized_class'] -> Class['other_class']
$local_var = $parameterized_class::param1
}
With an example usage of:
node default {
class { 'parameterized_class':
param1 => 'somevalue',
}
class { 'other_class': }
}
The above example does not work, as I get an error that looks roughly like:
Must pass param1 to
Class[Parameterized_class] at
/path/to/modules/parameterized_class/manifests/init.pp:1
on node localhost
Obviously, include is trying to declare parameterized_class without passing any parameters. But from the docs, I can see that include allows for a class to have been already previously declared, and since I have the parameterized_class declaration as a dependency of other_class, I don't understand how I could be getting this error.
I'm using Puppet 3.4.3, the version available on Ubuntu 14.04 Trusty
How should I go about retrieving the value of the $param1 in parameterized_class from within other_class's scope? Is it not possible to use include on parameterized classes?
According to the Puppet documentation (https://docs.puppet.com/puppet/3.5/lang_classes.html#include-like-behavior) you cannot use include-like declarations with mandatory parameters. In your case, what you can do is just not bother with the include since you've already handled that by declaring it in your node definition. Also, because both are declared in your node definition you would want to order them there as well.
As a side note not providing default values is a bad practice as is using variables across modules.

define keystone_user from openstack/puppet-keystone via hiera?

I am using https://github.com/openstack/puppet-keystone to set up an OpenStack management/controller node. I need to add the 'glance' user to keystone. I want to try and do as much as I can in my hiera data so my manifest will be simple.
Here is my manifest:
class kilo2_keystone {
include controller_ceph
include keystone
include keystone::config
include keystone::user
# keystone_user { 'glance':
# ensure => present,
# }
}
The commented out section works, but I want to be able to do include keystone::user and supply the parameters in my hiera data like so:
keystone::user:
"%{hiera('glance_admin_user')}":
ensure: present
But when I run puppet agent -t on my node I get this error:
Could not find class ::keystone::user
The commented-out code declares a resource of type keystone_user, not a class. Presumably its type, keystone_user, is provided by the puppet-keystone module. The include() family of functions are for declaring classes, not resources, so they are inapplicable to keystone_user.
There is more than one way you could proceed. If you don't anticipate wanting to anything more complicated than declaring one or more keystone_users present, then I'd recommend giving your class a parameter for the user name(s), to which you can assign a value via Hiera:
class kilo2_keystone($usernames = []) {
include controller_ceph
include keystone
include keystone::config
keystone_user { $usernames:
ensure => present,
}
}
On the other hand, if you want to be able to declare multiple users, each with its own set of attributes, then the create_resources() function is probably the path of least resistance. You still want to parameterize your class so that it gets the data from Hiera via automated data binding, but now you want the data to be structured differently, as described in the create_resources() docs: as a hash mapping resource titles (usernames, in your case) to inner hashes of resource parameters to corresponding values.
For example, your class might look like this:
class kilo2_keystone($userdata = {}) {
include controller_ceph
include keystone
include keystone::config
create_resources('keystone_user', $userdata)
}
The corresponding data for this class might look like this:
kilo2_keystone::userdata:
glance:
ensure: present
enabled: true
another_user:
ensure: absent
Note also that you are placing your kilo2_keystone class in the top scope. You really ought to put it in a module and assign it to that module's namespace. The latter would look like this:
class mymodule::kilo2_keystone($userdata = {}) {
# ...
}

Is it a convention to have a minimal init.pp that class-scopes the module?

I've come across the following convention, the init.pp is as minimal as possible and looks like this for the example of a java8 module in modules/java8/init.pp
import "*"
class java8 {
include java8::java8
}
Then a modules/java8/java8.pp defines the actual rules/implementations:
class java8::java8 {
# ...
}
Is this a convention, is it an old convention and deprecated? What would or is the rational behind this?
I'm not familiar with that style as any widely-used convention, and I see only limited value to it. Specifically, it appears to serve as a compromise between code organization interests and usage interests: it allows that every class of consequence will be defined in a manifest file named after it (including the delegate main class, java8::java8, in modules/java8/manifests/java8.pp), while providing a main class for the module with a one-segment qualified name (java8), so that users can simply
include 'java8'
I think it's fairly common nowadays to keep the main class small by making it delegate the details to other, private, classes inside the module, but I don't see much value in delegating to exactly one other class for (apparently) naming purposes alone. I also think it's potentially confusing to have different classes with the same unqualified name (java8) in the same module.

resource ordering synchronization issue "->" doesn't work?

I have encounter really weird behaviour which goes against what I have learned, tutorial says etc. So I would be glad if someone could explain why that is happening.
I have a role module which is made up of composition of profiles (role-profile pattern). My role consists:
class role::lab_prg_c2_dn inherits lab_prg_c2 {
class { 'profile::cluster_data_node':
namenode_fqdn => $role::lab_prg_c2::namenode_fqdn,
secondarynamenode_fqdn => $role::lab_prg_c2::secondarynamenode_fqdn,
}
->
class{'bigdatasolution':}
}
First class installs technology and second one installs our components and items which are build on top of technology. Hence the technology need to be installed first, thats the reason for "->" dependency. However this seems to me doesn't work correctly. As components from class 'bigdatasolution' are installed somewhere before the class profile::cluster_data_node finishes.
I tried to use require => Class['profile::cluster_data_node'] but that doesn't make any difference!
The content of class{'bigdatasolution':} :
class bigdatasolution {
$hdfs_default_conf = '/usr/local/hadoop.hdfs.conf'
$hbase_default_conf = '/usr/local/hadoop.hbase.conf'
include symlinks
include bdjar
}
Symlinks - create symlinks for the configuration installed in class profile::cluster_data_node and are not directly managed - it will be presented when actually specified package get installed.
bdjar - add our jar to a technology library so content is as follows:
class bigdatasolution::bdjar {
file { "/usr/lib/hadoop/lib/bigdata-properties.jar":
ensure => present,
mode => 0644,
group => 'root',
owner => 'root',
source => "puppet:///modules/bigdatasolution/bigdata-properties.jar"
}
}
I even tried to put require => "technologycalClass" here but that doesn't help either.
Can someone please help me understand what's wrong and how that should be solved properly?
I Using puppet 3 and ordering is specified explicetly - so no arbitrary ordering set by puppet should happen.
Thanks
If your 'profile::cluster_data_node' class 'includes' other classes/modules they will have no dependency ordering with the 'bigdatasolution' class.
I see you actually do include symlinks and bdjar. Basically every piece of ordering you want to have in puppet, you need to write explicitly.
Here you should replace the include statements with require, that way the class cluster_data_node will require the other two modules to complete before it says it has completed. Include is a pretty lose way of importing things in puppet and in my opinion is best to just avoid it and go with explicit require statements instead.
TL;DR: included modules have no transitive ordering; required modules do.

Resources