Avoiding duplicate definitions

4,571 views
Skip to first unread message

Thomas Sturm

unread,
Mar 6, 2012, 7:27:46 AM3/6/12
to Puppet Users
Hello Puppeteers,

one problem we stumble upon quite often is duplicate definition of
resources. For instance we install the package git-core in our base-
class every node is in. Now we want to use a module from github, e.g.
https://github.com/uggedal/puppet-module-git, but this one also
defines the package git-core and we have to find ugly fixes around the
resulting error.

As far as I understood puppet, there are two solutions:
1) wrapping each possibly problematic statement into a "if !
defined(Type["bla"])".
2) Defining all those resources virtually and just realize them in the
modules.

Both solutions don't help when taking this git module from github,
because we'd have to change it, it would no longer be an atomic piece
of logic one can just take and use unchanged. Is there some kind of
best practice for this problem? Or is there some other workaround I
don't know of or I didn't understand so far?

Thanks for any suggestions!
Thomas

Bruce Richardson

unread,
Mar 6, 2012, 12:02:47 PM3/6/12
to puppet...@googlegroups.com
On Mon, Mar 05, 2012 at 11:27:46PM -0800, Thomas Sturm wrote:
> Both solutions don't help when taking this git module from github,
> because we'd have to change it, it would no longer be an atomic piece
> of logic one can just take and use unchanged. Is there some kind of
> best practice for this problem? Or is there some other workaround I
> don't know of or I didn't understand so far?

You haven't missed anything. Virtual resources *are* the best practice
for avoiding duplicate definitions, such as it is. However, you won't
see them used a lot for package resource declarations; well-written
Puppet modules tend to encapsulate a discrete function, so package
conflicts tend to be rare (at least, within an organisation's own code).

Personally, I believe strongly in keeping puppet code as simple as
possible and only adding complexity (e.g. virtual definitions) where a
specific situation requires it. Adding layers of abstraction to code in
Puppet's declarative DSL causes more pain than it solves.

You have a choice of altering the third party code or your own. You
will keep encountering this problem if you use third party modules. I
guess you could do create your own safe package wrapper, something like
this:

define safepackage ( $ensure = present ) {
if !defined(Package[$title]) {
package { $title: ensure => $ensure }
}
}

And either use it everywhere (not necessarily a good idea) or wherever
you hit a problem with third party code.

Your problem is relevant to the earlier post about code reuse. I
considered responding to that (too busy, sorry) and this was one of the
kinds of scenarios that I had in mind.

--
Bruce

I must admit that the existence of Disneyland (which I know is real)
proves that we are not living in Judea in AD 50. -- Philip K. Dick

jcbollinger

unread,
Mar 6, 2012, 5:53:57 PM3/6/12
to Puppet Users


On Mar 6, 6:02 am, Bruce Richardson <itsbr...@workshy.org> wrote:

> You have a choice of altering the third party code or your own.  You
> will keep encountering this problem if you use third party modules.  I
> guess you could do create your own safe package wrapper, something like
> this:
>
> define safepackage ( $ensure = present ) {
>         if !defined(Package[$title]) {
>                 package { $title: ensure => $ensure }
>         }
>
> }
>
> And either use it everywhere (not necessarily a good idea) or wherever
> you hit a problem with third party code.


I'd recommend *not* using such a wrapper at all, mainly because
testing for resource definitions via the defined() function introduces
a parse-order dependency.

If you decide to use such a wrapper anyway, then you should use it
absolutely everywhere, including updating all third-party modules you
employ. I think it's better, though, to just let the compilation
failures happen -- use them to detect where you need to patch up
conflicts between modules.


John

Bruce Richardson

unread,
Mar 6, 2012, 6:19:58 PM3/6/12
to puppet...@googlegroups.com
On Tue, Mar 06, 2012 at 09:53:57AM -0800, jcbollinger wrote:
>
> If you decide to use such a wrapper anyway, then you should use it
> absolutely everywhere, including updating all third-party modules you
> employ. I think it's better, though, to just let the compilation
> failures happen -- use them to detect where you need to patch up
> conflicts between modules.

^This. I only offered the wrapper since a solution was requested.


--
Bruce

What would Edward Woodward do?

Mike Frisch

unread,
Mar 19, 2012, 1:29:49 AM3/19/12
to puppet...@googlegroups.com


On Tuesday, March 6, 2012 12:53:57 PM UTC-5, jcbollinger wrote:
employ.  I think it's better, though, to just let the compilation
failures happen -- use them to detect where you need to patch up
conflicts between modules.


I agree with this, however I have a scenario where the end-user could arbitrarily select 3 different modules, all of which include "package { 'httpd': ; }", for example.  None of the modules are requiring patching as they all legitimately use and depend upon Apache.  Is there any possibility of a workaround for this?

I'm using Puppet in a place where there's wrapper logic around including Puppet modules, which interfaces with an ENC.

jcbollinger

unread,
Mar 19, 2012, 1:39:13 PM3/19/12
to Puppet Users


On Mar 18, 8:29 pm, Mike Frisch <mike...@gmail.com> wrote:
> On Tuesday, March 6, 2012 12:53:57 PM UTC-5, jcbollinger wrote:
>
> > employ.  I think it's better, though, to just let the compilation
> > failures happen -- use them to detect where you need to patch up
> > conflicts between modules.
>
> I agree with this, however I have a scenario where the end-user could
> arbitrarily select 3 different modules, all of which include "package {
> 'httpd': ; }", for example.  None of the modules are requiring patching as
> they all legitimately use and depend upon Apache.  Is there any possibility
> of a workaround for this?


On the contrary, all three modules require patching if they are
supposed to be usable together. It is incorrect for them to each
declare Package['httpd'] in that scenario. That's what the errors are
telling you (just as they should).

If these three modules each depend on httpd but not on each other,
then that means none of them is a suitable owner for the httpd
package. You need to create a new module for managing httpd itself,
and let the three existing modules depend on that. As long as your
declaration of the httpd package does not need to depend on class
parameters, you can do this without touching your ENC. For instance:


class apache::base {
package { 'httpd':
ensure => latest
}

service { 'httpd':
haststatus => true,
hasrestart => true,
enable => true,
ensure => running
require => Package['httpd']
}
}


class mymodule::httpdstuff {
include 'apache::base'
# ...
}


> I'm using Puppet in a place where there's wrapper logic around including
> Puppet modules, which interfaces with an ENC.


That doesn't mean much to me. If it places relevant constraints on
what you can do then you'll need to explain.


John
Reply all
Reply to author
Forward
0 new messages