19

I'm writing some puppet modules and have a package defined in two modules hence get the following error:

err: Could not retrieve catalog from remote server: Error 400 on SERVER: Duplicate definition: Package[gnome-session-fallback] is already defined in file /etc/puppet/modules/vnc4server/manifests/init.pp at line 3; cannot redefine at /etc/puppet/modules/vino/manifests/init.pp:7 on node l

Hence want to ensure that the package has not already been defined but the following does not work:

if ! defined ('gnome-session-fallback') {
    package { 'gnome-session-fallback':
        ensure => installed,
    }
}

Can anyone suggest how to fix this, and on the broader scale, what is the "proper" approach to avoiding clashes such as this in modules?

Mr Morphe
  • 664
  • 1
  • 7
  • 15
  • Please post exactly how this does not work. Do you get an error message, or it just simplz does not do what it is supposed to? Also please include which version of Puppet you are using! – ppeterka Mar 07 '13 at 08:35
  • Error message posted on the second line above - I am testing if its already defined in another module and the test does not seem to detect this and hence attempts to redefine it and the agent run fails (see err). Version 2.7.11 – Mr Morphe Mar 07 '13 at 08:44
  • Maybe I'm a bit dull today: so you get the error with the `if ! defined...` script, right? – ppeterka Mar 07 '13 at 08:47
  • The error is as posted in the original post "Error 400 on SERVER: Duplicate definition: Package" etc because the if ! defined test is not working. – Mr Morphe Mar 07 '13 at 11:05
  • See [my comment below](http://stackoverflow.com/questions/15266347/puppet-test-if-a-package-already-defined#comment60811703_15317014), @MrMorphe. – Greg Dubicki Apr 13 '16 at 19:10

4 Answers4

46

You are missing Package[] inside defined(). The correct way to do it:

if ! defined(Package['gnome-session-fallback']) {
    package { 'gnome-session-fallback':
        ensure => installed,
    }
}
Gergo Erdosi
  • 40,904
  • 21
  • 118
  • 94
  • 3
    Note that it doesn't work in all cases because defined() is [dependent on parse order](https://docs.puppet.com/puppet/4.4/reference/function.html#defined) and there's a [bug for it opened for a long time](https://tickets.puppetlabs.com/browse/PUP-1417). – Greg Dubicki Apr 13 '16 at 19:08
13

The cleanest way to do this is to use the ensure_resource function from puppetlabs-stdlib:

ensure_resource('package', 'gnome-session-fallback', {'ensure' => 'present'})

aetimmes
  • 131
  • 1
  • 4
  • 8
    an even cleaner function to do this from said library is `ensure_packages(['pkg1', 'pkg2'])` – Zaroth Jul 15 '15 at 11:43
5

To answer my own question about what the "proper" approach is : This issue is discussed at https://groups.google.com/forum/?fromgroups=#!topic/puppet-users/julAujaVsVk and jcbollenger offers what looks like a "best-practice" solution - resources which are defined multiple times should be moved into their own module and included into the classes on which they depend. I applied this and solved my problem.

This doesn't actually answer why "if !defined" fails however...

Mr Morphe
  • 664
  • 1
  • 7
  • 15
1

One cleaner way (among multiple ways) is to create a virtual package resource and then realize it. You can realize the same virtual package multiple times without error.

@package { 'gnome-session-fallback':
    ensure => installed,
}

And then where you need it:

realize( Package[ 'gnome-session-fallback' ] )