Managing common resources with roles and profiles

Hi,

I'm quite new to Puppet, and have spent quite a lot of time reading the docs and researching how best to organise our manifests. As a developer, the roles and profiles pattern makes a lot of sense, but I'm still struggling with some fundamental problems. In particular, I am unsure of a good way to manage common resources, such as packages that are required by multiple roles or profiles, especially when we use some third-party Forge modules that explicitly declare package resources.

By way of an example, let's assume I have a web server role and a job queue role. The application profile is common to both:

class acme::role::web_server {
include acme::profile::application
include acme::profile::web_server
}

class acme::role::job_queue {
include acme::profile::application
include acme::profile::gearman
}


Each profile defines the components that it requires to operate as a standalone unit. The examples show each component as a separate module that can be included, but that doesn't have to be the case - the resources could be declared directly in the profile:

class acme::profile::application {
include acme::component::network
include acme::component::ntp
include acme::component::application
}

class acme::profile::web_server {
include acme::component::network
include acme::component::ntp
include acme::component::httpd
}

class acme::profile::gearman {
include acme::component::network
include acme::component::ntp
include acme::component::application
include acme::component::gearman
}


The network and ntp components are common to all profiles, and could therefore be placed in a parent class from which all others inherit. It's a trade-off between duplication and each profile being explicit.

Now let's say that the application component and the gearman component both share common package requirements, such as gcc and memcached. I can't explicitly declare those dependencies in both my application and gearman components because that will cause duplicate resource errors. I could define those dependencies as virtual resources, and then realize them in my components:

class acme::packages {
@package {['gcc', 'memcached']: ensure => 'installed'}
}

class acme::component::application {
include acme::packages
realize Package['gcc', 'memcached']
...
}


But let's also say that a third-party Forge module used by the gearman component already explicitly installs the gcc package. That will cause a conflict with my virtual gcc package definition. The simple solution is to remove my virtual gcc package definition, but then the fact that my components require gcc is lost. I could comment it out, with a note that explains the problem, but that's starting to get really messy:

class acme::packages {
@package {[
# 'gcc', Installed by third-party module
'memcached'
]: ensure => 'installed'}
}

class acme::component::application {
realize Package[
# 'gcc', Installed by third-party module
'memcached'
]
...
}


I could decide not to use the Forge module, but then I'd have to rewrite the useful bits. I could edit the module, but that makes upgrading difficult. After some digging around, I found the constraints module, which allows me to explicitly specify my component's dependencies, without actually declaring them as resources:

class acme::component::application ...
edit retag close merge delete

Did you ever find a resolution to this issue? I've come to the same problem. I have two profiles that require a common component (e.g. ssh). Most component modules seem to use templates so we would have to have duplicate declarations.

( 2017-05-04 09:44:04 -0500 )edit

While we could provide all required parameters to the component directly, we then lose the explicit requirement for the component within the profile.

( 2017-05-04 09:44:52 -0500 )edit

Sort by » oldest newest most voted

The puppetlabs-stdlib package provides ensure_resource. You could use it like:

class acme::role::web_server {
ensure_resource(
'package',
['memcached','gcc'],
{ ensure => 'installed' },
)
include acme::profile::application
include acme::profile::web_server
}

class acme::role::job_queue {
ensure_resource(
'package',
['memcached'],
{ ensure => 'installed' },
)
include acme::profile::application
include acme::profile::gearman
}

more