I'm having trouble with puppet (version 5.5) code design. I've written a component module to deal with ucarp. It make use of the module eyp-systemd to register an ucarp service within systemd. Now I would like to consume the ucarp module from two independant profile modules that manage different services (in my case actually haproxy and bind9). Essentially this looks like this:
class ucarp {
systemd::service { 'ucarp':
# list of parameters
}
}
define ucarp::vip {
# defines a virtual IP to be shared among several nodes
}
# ====================
class profile_haproxy {
include ::ucarp
::ucarp::vip { 'haproxy': }
# setup haproxy
}
# =====================
class profile_bind9 {
include ::ucarp
::ucarp::vip { 'bind9': }
# setup bind9
}
This is straight forward and works well.
Now the actual issue: it is best practice to order the ucarp service after the services that are run over ucarp. This is possible using the after parameter:
class ucarp(
Array[String] $after,
) {
systemd::service { 'ucarp':
after => $after.join(' '),
# list of other parameters
}
}
This requires replacement of include ::ucarp
by
class { '::ucarp':
after => ['haproxy'],
}
or
class { '::ucarp':
after => ['bind9'],
}
respectively. Of course this would immediately lead to a "duplicate declaration" error.
What I actually would like to have is a single instantiation of the class ucarp that collects all after
parameters into one single string that can be passed to systemd::service. How would I do this?
Currently two possible solutions come to my mind:
- Fork eyp-systemd, remove the after parameter and replace it by a defined type, e.g.
systemd::service::after
that manages the corresponding entry in the service definition file. This is something I really don't want to do. Generally I shy away from modifying forge modules as I this forces me to maintain them on my own. In this case the change also seems to be rather big (including an interface change). - Introduce my own defined type in the ucarp module
ucarp::order_after
which does not do anything. The profile modules would define virtual instances of this type. The ucarp class could then use a puppetdb query to collect all instances ofucarp::order_after
. The big drawback here is that I'm only dealing with virtual resources not with exported resources. So actually there is no need at all to involve puppetdb, rendering this approach to an ugly work-around.
A further solution is inspired by c4f4t0r:
- Introduce an ucarp profile module that single task is to instantiate the ucarp component class with the correct
after
services. The list ofafter
services is provided by hiera:
class profile_ucarp ( Array[String] $after, ) { class { '::ucarp': after => $after, } }
profile_ucarp.after: - 'haproxy' - 'bind9'
There is no need any more for the other profile classes to instantiate theucarp
class - removing the potential duplicate declaration issues. I consider this solution superior to the two above. Still I'm not content as using hiera to fix an issue that is solely related to code is a misuse of hiera.
I hope there are other possibilities I can't think of right now.