puppet - how to ship same config file using two different classes? - puppet

I'm shipping a specific config file with puppet to all my computers. Let's call this class class A:
class A {
# ship lightdm file
file {
"/etc/lightdm/lightdm.conf":
mode => 644,
owner => root,
group => root,
ensure => file,
require => Package["lightdm"],
source => "puppet:///modules/my_module/lightdm.conf";
}
}
class A will actually be loaded through some other class:
node 'somecomputer' {
include role::my_role #(will load class A)
}
Now, some user needs a special version of that particular config file. So I thought about writing a class B (which would look the same as A except for the source part) and include that class for the node config of that particular computer:
node 'specialcomputer' {
include role::my_role #(will load class A)
include B
}
However, I'm wondering how puppet will determine which file to ship in the end. Since there's no order of execution in puppet, it seems to me like my current approach won't work (plus the resource file will be defined twice which won't work either)
I also can not use inheritance on class A because class A is included by some top level class. So how should I deal with this case? any pointers?

If you provide multiple sources, it will select the first that is available:
file {
"/etc/lightdm/lightdm.conf":
mode => 644,
owner => root,
group => root,
ensure => file,
require => Package["lightdm"],
source => [ "puppet:///modules/my_module/lightdm-${::fqdn}.conf",
"puppet:///modules/my_module/lightdm.conf" ],
}
Then you would have 2 files in the files directory:
files/lightdm.conf (for all hosts)
files/lightdm-specialcomputer.domain.com.conf (for the exception)
It's not exactly what you asked for, but I think that is what you want...

Related

How do I apply only one file or two classes from a Puppet Master server?

Let us say that I have a case in which I need to apply only two files from a Puppet configuration on some production servers, without touching the rest of the configuration.
/opt/aservice/myfile/thekey.conf
/opt/myfile/thekey.salt
Let's also say that these are controlled by the following Puppet manifest:
#
# author: Nathan Basanese (nathan#basanese.com)
# date: 04/17/2048
#
class keyconfig ( $cluster ){
notify {"Deploying key config. files to $fqdn":}
file {'/opt/aservice/key/config/thekey.conf':
ensure => present,
mode => '0644',
owner => 'aservice-serv',
group => 'aservice-serv',
source => "puppet:///modules/keyconfig/$cluster/thekey.conf",
}
file {'/opt/aservice/key/config/thekey.salt':
ensure => present,
mode => '0644',
owner => 'aservice-serv',
group => 'aservice-serv',
source => "puppet:///modules/keyconfig/$cluster/thekey.salt",
}
}
How would I apply ONLY these two files to a given server from a Puppet Master?
Perhaps, in the puppet agent command that is run on the target server, could I specify a specific Puppet class to use?
I have used the puppet resource command before, but I'm not sure that would work, here.
Every resource is automatically tagged with the fully qualified name of the class or defined type in which it is declared, and with every namespace segment of the class or type name, among other tags. You can use those tags to filter the resources that will be applied during a given catalog run. In the particular example you describe, you could use
puppet agent --no-daemonize --onetime --tags keyconfig
to apply only the resources declared in class keyconfig (and in any other class declared by keyconfig, recursively, but in this case there are no such other classes).
You can also declare tags manually by using the tag metaparameter in your resource declarations. That can allow you to provide for identifying custom collections of resources. And speaking of collections, you can use tags in the selection predicates of resource collectors, too.
The only way to do that is to have that node contain only the class you are wanting to have applied. In your site.pp you would have the following where the 'myhost.dns' is your fqdn. and $mycluster would be replaced by your cluster string.
node 'myhost.dns' {
class { 'keyconfig':
cluster => $mycluster,
}
}

Restarting a service of other class, while depending on the other class, creates a dependency cycle

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.

Can Hiera lookups be done in a module?

I have a service implemented in Java which depends on 3 property files. I have defined 'define' for each of the property file in a common properties module and consuming them from service specific module. The 'define' for one of the property file is shown below:
define properties::rabbitmq (
$property_file,
$service_name,
$rabbitmq_host,
$rabbitmq_username,
$rabbitmq_password,
$rabbitmq_port,
$rabbitmq_vhost) {
file { $property_file:
ensure => file,
content => template('config/rabbitmq.properties.erb'),
mode => '0644',
notify => Service[$service_name],
}
}
I am following roles and profile pattern in my puppet code and doing all hiera lookups in service specific profile. Now because of this whenever there is a change in property files, I need to make cascading changes to all of my puppet modules that consumes that property file. The changes are needed in profile (hiera lookup), module init.pp (addition/removal of parametes from constructor) and config.pp (parameter adjustment when invoking 'define' for a property file).
I feel that the above problem can be solved by incorporating hiera lookups in 'define' for a property file, like this:
define properties::rabbitmq ($property_file, $service_name,) {
$rabbitmq_host = hiera('rabbitmq_host')
$rabbitmq_username = hiera('rabbitmq_username')
$rabbitmq_password = hiera('rabbitmq_password')
$rabbitmq_port = hiera('rabbitmq_port')
$rabbitmq_vhost = hiera('rabbitmq_vhost')
file { $property_file:
ensure => file,
content => template('config/rabbitmq.properties.erb'),
mode => '0644',
notify => Service[$service_name],
}
}
But, above is a violation of roles and profile pattern. The above is doing hiera lookup in a module instead of doing it in profile. Now, the module has a tight dependency on hiera. It being an internal module (not meant for puppet forge), I guess, it should be OK to violate the guideline in favor of code maintainability.
I seek opinion from others on above.

Do puppet conditionals ensure order, or do I still need to add metaparameters

I have code similar to the following:
class someclass($ensure = installed)
{
if($ensure == installed)
{
$installValue = installed
file { "someprogram.msi":
ensure => file,
source => 'somewhere',
path => 'C:/puppet-files/someprogram.msi',
}
}
else
{
$installValue = absent
}
package{ "someprogram":
ensure => $installValue,
source => 'C:/puppet-files/someprogram.msi',
}
}
Does the if statement containing the file resource ensure that the file resource will get applied before the package resource? Or do I need to explicitly state this in the metaparameters? Also, I am assuming that the $installValue will always be set before the package is installed, is that correct?
Thank you,
Derongan
You should specify the ordering explicitly, however the variable will be initialised correctly.
The ordering of resources in Puppet 3 is deterministic, but essentially random as it's based on hashes of the resource titles. In Puppet 3.3, this behaviour can be changed to the manifest order (release notes), but I wouldn't recommend relying on this - certainly if you're sharing the module, there's no guarantee that others use the same setting.
Since the file resource may not exist (if ensure => absent), you can't specify the relationship on the package resource. Instead, add before => Package['someprogram'], to the file resource.

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