I need to execute class mysql,tomcat before I execute code in class mypackage. In my site.pp I have
node 'node1' {
include mysql,mypackage,tomcat
}
How do I ensure the order of execution mysql->tomcat->mypackage
I tried putting this in /etc/puppet/modules/mypackage/manifests/init.pp but it did not work.
class mypackage {
include mysql
include tomcat
}
Please read this article about ordering in puppet.
UPDATE:
I recommend defining ordering relationships in your site.pp
node 'node1' {
include mysql,mypackage,tomcat
Class['mysql'] -> Class['tomcat'] -> Class['mypackage']
}
Please be aware of dependency cycles. It is really easy to create such cycle in puppet.
Related
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.
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
In puppet, I have the following two classes:
class zabbix-agent {
package { 'zabbix-agent': }
->
service { 'zabbix-agent':
ensure => running
}
}
class zabbix-agent-cassandra {
include zabbix-agent
Class['zabbix-agent']
->
file { '/etc/zabbix/zabbix_agent.conf.d/cassandra.conf':
}
~>
Service['zabbix-agent']
}
This looks great at first, since it allows to add new configurations files to /etc/zabbix/zabbix_agent.conf.d/ from any class, and to restart zabbix-agent when doing so.
However there is a dependency cycle:
Service[zabbix-agent] => Class[Zabbix-agent] => File[/etc/zabbix/zabbix_agentd.conf.d/cassandra.conf] => Service[zabbix-agent]
It there a way to avoid the dependency cycle ?
You're telling Puppet to
manage the zabbix package and service
do this before managing the config file
if the config file changed, manage the service (again)
This is problematic, given that Puppet will touch each resource exactly once.
The best approach will likely be to bring more structure to your zabbix module.
class zabbix::agent {
include zabbix::package
include zabbix::service
Class['zabbix::package'] -> Class['zabbix::service']
}
This allows you to just
Class['zabbix::package'] -> File[...] ~> Class['zabbix::service']
which is DRYer and, in your particular case, avoids circular dependencies.
I'm new to puppet and I'm trying to figure out how to get different hosts installing different packages, but I've stumbled upon an issue I can't figure out. These are my manifests:
My site.pp:
node default {
}
node 'debh3' inherits default {
}
node 'debh4' inherits default {
import "db"
}
node 'master' inherits default {
}
My db.pp:
package { 'mysql-server':
ensure => installed
}
service { 'mysql':
ensure => true,
enable => true,
require => Package['mysql-server']
}
With this setup, mysql-server is being installed on debh3.
If I replace the "import db" with the actual code inside my db.pp, then mysql-server is only installed on debh4 (which is the behaviour i'm after).
Does anyone have a clue what I'm doing wrong here? I've put it all in site.pp to ensure there are no other dependencies affecting anything.
Also note that the import statement is deprecated and about to be removed from Puppet 4.0.
You should move your code to modules. In this case, you want to create a db module.
In /etc/puppet/modules/db/manifests/install.pp
class db::install {
package { 'mysql-server':
ensure => installed
}
}
an in /etc/puppet/modules/db/manifests/service.pp
class db::service {
include db::install
service { 'mysql':
ensure => true,
enable => true,
require => Class['db::install'],
}
}
From you node block, you can then just
include db::install
include db::service
or even just include db::service.
You could have both resources in one class, but it's good practice to structure your code through multiple classes.
Upon further digging, I found this in the "import" documentation at https://docs.puppetlabs.com/puppet/latest/reference/lang_import.html:
Import statements have the following characteristics:
They read the contents of the requested file(s) and add their code to top scope
They are processed before any other code in the manifest is parsed
They cannot be contained by conditional structures or node/class definitions
These quirks mean the location of an import statement in a manifest does not matter.
This points to why what I was doing was incorrect and why it caused the behaviour. As for a solution, I will look into best practices and determine the "correct" way to structure my manifests.
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.