puppet style, what does "prefer metaparameters to relationship declarations" *mean*? - puppet

Looking at the Relationship Declarations section in the Puppet Style Guide about the '->' arrows, where 'x->y' means that y requires x to be installed before y, it says:
When possible, you should prefer metaparameters to relationship declarations.
that's a lot of syllables. Is that saying that you should prefer this
file { "/home/${user}/.ssh":
require => User[$user],
...
}
and not use the arrows like this?
User[$user] -> file { "/home/${user}/.ssh":
...
}

file { "/home/${user}/.ssh":
require => User[$user],
...
}
1.The above code even works with different manifests, when they are part of same catalog. So if you use metaparameters you have less work when you get a modification in future(unfortunately).
2.Chaining arrows is best used for Resource collectors, when you have to make relationship more than one resource, you can have this instead of putting require/before in all the resources.

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.

Puppet cron job -- ensure files exist

I'm trying to set up a Puppet cron job with the following structure:
file { '/usr/local/sbin/file.py':
mode => '0755',
source => 'puppet:///modules/file.py',
require => File['/usr/local/sbin']
}
cron { "cronjob":
require => "ALL_THE_FILES_ABOVE"
command => "...command_to_run_script..."
minute => '*/1'
}
All of the above is in one file run_script.pp. I'm wondering how I can code the require => "ALL_THE_FILES_ABOVE" part.
Thanks!
Based on the information provided in your question, I am going to make the assumption that the contents of run_script.pp is many file resources and the listed cron resource. You state that you want the cron resource there to require all of the file resources in that class. Based on this, here is a clean and efficient solution.
There are a few complicated/advanced ways to arrive at a clean and efficient solution, but the easiest to understand is to use a resource default: https://puppet.com/docs/puppet/5.3/lang_defaults.html
With this, we can establish attribute/value pair defaults for all file resources contained in that scope. This would make it easier to use the before metaparameter on the file resources instead: https://puppet.com/docs/puppet/5.3/metaparameter.html#before
This simplifies the solution to a one-liner in your class:
File { before => Cron['cronjob'] }
Note there will be a caveat to this method, which is that if you are declaring, requiring, or containing a class within this manifest, then this default could be expanded to that "area of effect" and cause a circular dependency. In that case, you should use a per-expression resource default attribute: https://puppet.com/docs/puppet/5.3/lang_resources_advanced.html#per-expression-default-attributes
You can use a multiple require
file{'path/foo':}
file{'path/bar':}
file{'~/foobar':
require => [ File['path/foo'], File['path/bar'] ]
}
or you can use the ordering arrow
-> (ordering arrow; a hyphen and a greater-than sign) — Applies the resource on the left before the resource on the right.
file{'path/foo':} ->
file{'path/bar':} ->
file{'~/foobar':}
Here is more information about relationships and ordering in Puppet

Conditional logic on whether to include subclass

I'm trying to edit the init.pp file to only include a subclass if a variable has been set. I've initialized the variables as undef, however when I do the IF statement as below it errors and says:
Syntax error at 'if'; expected '}'
When I write it as a case statement, it works fine but not as an IF. Any idea why that is?
class {'wlsvr':
}
->
case $jdbc_filename {
undef: {}
default: {class {'jdbc':}}
}
->
if $managedsvr_name != undef {
class {'managedsvr':
}
}
Please rid yourself of the unfortunate habit of using
->
between every other Puppet statement.
This chainging arrow introduces a dependency between the resources/classes it connects. This should be used only when a dependency is actually needed. Issues you are opening yourself to
gratuitous dependency trees when building dependencies between classes (you do that here)
issues when refactoring code, because if and cases statements do not (always) form the equivalent of resources or classes
As an aside, it is also beneficial to avoid the
class { 'classname': }
syntax for declaring classes and prefer
include classname
instead, because the former costs you the singleton semantics of Puppet classes.
Using an chaining arrow before an if statement is illegal syntax. From the puppet documentation on Relationships and Ordering:
Operands
The chaining arrows accept the following types of operands on either side of the arrow:
Resource references, including multi-resource references
Resource declarations
Resource collectors
I'm not sure why it allows case statements and not if statements, but I don't think it's best practice to chain either of them.

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.

Puppet DSL: order does not matter?

According to the Puppet documentation:
Order does not matter in a declarative language.
If that is the case, why does this bit of code work:
class myserver {
$package_to_install = 'libcapture-tiny-perl'
package {
$package_to_install: ensure => present;
}
}
but this code does not work:
class myserver {
package {
$package_to_install: ensure => present;
}
$package_to_install = 'libcapture-tiny-perl'
}
If order matters, then I can see why one works and the other does not, but since order does not matter, why do they behave differently?
Disclaimer: I am one of the Puppet developers.
Because our language isn't, as our documentation claims, actually declarative. It is actually ordered. :(
Evaluation is more or less top to bottom inside the class or declaration. The product of that evaluation is a resource in the catalog, however, not evaluation of the catalog.
Think of the DSL as a not-entirely-declarative way to build the catalog, a graph of resources, that are entirely declarative in processing.

Resources