Reputation: 1156
I have a system which has different roles, A B C. There is a class daemon::conf
that defines the conf and concats the configs of all the classes arguments e.g.
class daemon::conf (
global_config = {}
a_config = {}
b_config = {}
c_config = {}
) {
concat::fragment {...}
}
So when I do this:
class hg_mysystem::mycluster::hybrid {
include daemon::A
include daemon::B
}
I want to have:
$ cat /etc/mysystem/config
[Global]
...
[A]
...
[B]
...
each daemon is defined as daemon::A, daemon::B, daemon::C
, but they call daemon::conf
with heir own parameters that are either defined in hiera on inside the .pp
manifest files. Now I need to create a node that has 2 or 3 roles (writing include daemon::A;include daemon::B
etc), but I get a problem with a class redefinition, because daemon::conf is defined in all A B and C.
My first thought was to define the class on one node and add if defined(Class['daemon::conf']) {add argument to the defined class} else {class{'daemon::conf'...}}
but I don't know how to create a dynamic hiera variable from a manifest, or how to do a hiera style assignment from a manifest.
I was also searching on how to do a lazy init of the class with those virtual resources, but I don't understand how could that help, when realize doesn't override an argument but with realize you only do this realise Class['daemon::conf']
and not realise Class['daemon::conf'] {b_config={...}}
.
Is there any way I can restructure daemon::conf
with subclasses that notify another class that builds the conf based on the classes' data.
Edit:
I followed the second approach and split daemon::conf
to daemon::conf
, daemon::conf::A
, daemon::conf::B
class daemon::conf (...) {
concat { '/etc/daemon/conf':
owner => 'root',
group => 'root',
mode => '0664',
require => Package['daemon'],
}
Concat::Fragment <<| target == '/etc/daemon/config' |>>
concat::fragment { 'daemon.conf':
tag => "daemon.conf",
target => '/etc/daemon/config',
order => '01',
content => template('daemon/daemon.conf.erb'),
}
}
define daemon::conf::A (...) {
include ::daemon::conf
@@concat::fragment { "${::hostname}.daemon.conf":
tag => "daemon.conf",
target => '/etc/daemon/config',
order => '20',
content => template('daemon/daemon.conf-A.erb'),
}
}
class daemon::conf::B (...) {
include ::daemon::conf
concat::fragment { $::hostname:
tag => "daemon.conf",
target => '/etc/daemon/config',
order => '10',
content => template('daemon/daemon.conf-B.erb'),
}
}
class daemon::A (
$A_addr,
$port,
) {
include ::daemon::conf
daemon::conf::A { $::hostname:
addr => $A_addr,
port => $port,
}
}
class daemon::B (
$B_rack_loc,
) {
include ::daemon::conf
class {'::daemon::conf::B':
B_config => {
B_rack_location => $B_rack_loc,
}
}
}
Running puppet on 3 nodes in the same hostgroup I should get:
[user@hostname1: ~]$ cat /etc/daemon/config
[Global]
...
[B]
loc = row RO, rack RA, host hostname1
[A/hostname1 ip]
addr=...
port=...
[A/hostname2 ip]
addr=...
port=...
[A/hostname3 ip]
addr=...
port=...
But instead I get multiple configs of role B as well of all 3 hosts. What mistake do I do and how to fix it? Thanks. Is it the "<<| |>>" statement that should be altered?
Upvotes: 0
Views: 282
Reputation: 180058
Any solution needs to accommodate the fact that the values of all of a given class's parameters are determined the first time a declaration of that class is evaluated, whether the declaration is a resource-like one or an include-like one. Multiple declarations are permitted only if all those evaluated after the first use one of the include-like forms, and this is among the reasons that resource-like class declarations should be avoided under most circumstances.
There are various ways to take those considerations into account. One would be to invert the logic: instead of having all each daemon::X
class declare daemon::conf
, declare it once, centrally, and pass it a list of roles to configure. Let it then declare appropriate daemon::conf::X
classes based on the role list:
class daemon::conf (
$global_config = {}
$roles = []
) {
concat { ... }
concat::fragment {...}
$roles.each { |$role|
contain "daemon::conf::${role}"
}
}
Another way would be to absolve the central daemon::conf
class from responsibility for declaring the per-role configuration at all. This is possible because you're using Concat to build your config from fragments. One of the key features of puppetlabs::concat is that concat::fragment
s can be declared independently of each other and of the concat
declaring the file to which they contribute:
class daemon::conf (
$global_config = {}
) {
concat { ... }
concat::fragment {...} # general configuration only
}
class daemon::a::conf (...) {
concat::fragment {...} # daemon A configs
}
class daemon::b::conf (...) {
concat::fragment {...} # daemon B configs
}
class daemon::a (...) {
include daemon::conf # (maybe)
contain daemon::a::conf
# ...
}
class daemon::b (...) {
include daemon::conf # (maybe)
contain daemon::b::conf
# ...
}
...
Upvotes: 2