1

I have a puppet module A. In that module I have a service restart for a change in file.

class A::test1 { 
  include ::corednsclient
  service { 'sshd':
    ensure => running,
    enable => true,
  }
}

Now , I have a different puppet module B. In that module also I have to restart the same service for a change in another file.

Now , the problem is that I'm getting the following:

Duplicate declaration error

when I'm doing /opt/puppetlabs/bin/puppet apply --modulepath=/abc xyz/site.pp

If I runs each module independently as puppet apply -e 'include moduleA' and puppet apply -e 'include moduleB' , Both would works fine. But puppet apply globally seems to be failing.

Any help would be highly appreciated !

Error: Evaluation Error: Error while evaluating a Resource Statement,
 Duplicate declaration: Service[sshd] is already declared in file 
 /export/content/ucm/puppet/modules/coresshd/manifests/configure.pp:28; cannot
 redeclare at 
 /export/content/ucm/puppet/modules/corednsclient/manifests/daemon_reload.pp:10 at 
 /export/content/ucm/puppet/modules/corednsclient/manifests/daemon_reload.pp:10:3 on 
 node lor1-0002276.int.xxx.com .
Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
melvil james
  • 592
  • 7
  • 18
  • Possible duplicate of [Duplicate declaration of same resource defined in separate classes](https://stackoverflow.com/questions/26205727/duplicate-declaration-of-same-resource-defined-in-separate-classes) – Alex Harvey Jun 21 '19 at 15:56

1 Answers1

4

Yes, this is normal. Puppet only allows resources to be declared once. In general, if you have code like:

class aaa {
  notify { 'xxx': message => 'yyy' }
}

class bbb {
  notify { 'xxx': message => 'yyy' }
}

include aaa
include bbb

Puppet apply that and you will see an error like this:

Error: Evaluation Error: Error while evaluating a Resource Statement,
 Duplicate declaration: Notify[xxx] is already declared at (file: ...test.pp, 
 line: 2); cannot redeclare (file: ...test.pp, line: 6) (file: ...test.pp, line: 6,
 column: 3) on node ...

Workarounds

Solution 1 Refactor so both classes inherit a third class

Generally, the best way to resolve this is to refactor your code so that there is a third class that contains the duplicated resource, and other classes include that using the include function, like this:

class ccc {
  notify { 'xxx': message => 'yyy' }
}

class aaa {
  include ccc
}

class bbb {
  include ccc
}

include aaa
include bbb

That works fine.

Note that this only works because the include function can be called any number of times, unlike a resource declaration - also unlike the resource-like class declarations.

You can read more about "include-like v resource-like class declarations" here.

Solution 2 Use virtual resources

You can also use virtual resources. Refactor like this:

class ccc {
  @notify { 'xxx': message => 'yyy' }
}

class aaa {
  include ccc
  realize Notify['xxx']
}

class bbb {
  include ccc
  realize Notify['xxx']
}

include aaa
include bbb

An added advantage of this one is you can use resource collectors and select only specific resources from a set of virtual resources, like this:

class ccc {
  @notify { 'ppp': message => 'xxx' }
  @notify { 'qqq': message => 'yyy' }
  @notify { 'rrr': message => 'zzz' }
}

class aaa {
  include ccc
  Notify <| message == 'xxx' |>
}

class bbb {
  include ccc
  Notify <| message == 'xxx' or message == 'yyy' |>
}

include aaa
include bbb

If you don't need this functionality here, as appears the case, you probably should use the first proposal.

Solution 3 Use ensure resource

Another option is the ensure_resources function in stdlib:

class aaa {
  ensure_resources('notify', {'xxx' => {'message' => 'yyy'}})
}

class bbb {
  ensure_resources('notify', {'xxx' => {'message' => 'yyy'}})
}

include aaa
include bbb

Solution 4 Use defined

Historically this is strongly advised against, although the docs do not mention any reason to not use it. It is possible to use the defined like this:

class aaa {
  if ! defined(Notify['xxx']) {
    notify { 'xxx': message => 'yyy' }
  }
}

class bbb {
  if ! defined(Notify['xxx']) {
    notify { 'xxx': message => 'yyy' }
  }
}

include aaa
include bbb

This way, the resource is added to the catalog only if it is not already in there.

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97