Duplicate declaration of same resource defined in separate classes
Asked Answered
P

4

16

I have a class definition which requires the build-essential package:

class erlang($version = '17.3') {

  package { "build-essential": 
    ensure => installed
  }
  ...
}

Another class in a different module also requires the build-essential package:

class icu {

  package { "build-essential": 
    ensure => installed
  }
  ...
}

However, when I try to perform puppet apply, the error I receive is:

Error: Duplicate declaration: Package[build-essential] is already declared in file /vagrant/modules/erlang/manifests/init.pp:18; cannot redeclare at /vagrant/modules/libicu/manifests/init.pp:17 on node vagrant-ubuntu-trusty-64.home

I was expecting classes to encapsulate the resources they use but this doesn't seem to be the case? How can I resolve this clash?

Pharynx answered 5/10, 2014 at 18:14 Comment(0)
B
20

This is common question when dealing with multiple modules.

There's a number of ways of doing this, the best practise is to modularise and allow the installation of build essential as a parameter:

class icu ($manage_buildessential = false){

  if ($manage_buildessential == true) {
   package { "build-essential": 
     ensure => installed
   }
 }
}

Then, where you want to include your ICU class:

class {'icu':
   manage_buildessential => 'false',
}

However, for a quick and dirty fix:

if ! defined(Package['build-essential']) {
    package { 'build-essential': ensure => installed }
}

Or if you have puppetlabs-stdlib module:

ensure_packages('build-essential')
Bullyrag answered 6/10, 2014 at 11:33 Comment(1)
Since I switched to ensure_packages my quality of life improved drastically. :)Durand
D
5

If you control both modules, you should write a third class (module) to manage the shared resource.

class build_essential {
    package { 'build-essential': ensure => installed }
}

Contexts that require the package just

include build_essential

Do not touch the defined() function with a 12" pole. There can be only pain down this road.

Dermis answered 6/10, 2014 at 16:40 Comment(0)
T
1

There are multiple ways as the other answers explain but this is another reliable way of doing it if you want to use the same resource multiple times.

Declare once and then realize it multiple times.. For example, Create a new virtual resource like this:

in modules/packages/manifests/init.pp

class packages {
  @package{ 'build-essential':
    ensure => installed
  }
}

Then, in your both classes, include the below lines to realize the above virtual resource

include packages
realize Package('build-essential')
Tizzy answered 8/4, 2019 at 3:26 Comment(0)
P
0

Following Martijn Heemels comment.
It looks like ensure_packages makes life match easier.

A nice example from this cookbook
Challenge: You want to manage a package from multiple places.

# Assumes you've already installed the puppetlabs-stdlib module

class strace {
  notify { 'In strace': }
  ensure_packages(['build-essential'], { ensure => 'present' })
}

class debug_tools {
  # install lots of debug tools, and then strace
  notify { 'In debug_tools': }
  ensure_packages(['build-essential'], { ensure => 'present' })
}
Phthisis answered 1/3, 2023 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.