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 .
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 ...
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.
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.
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
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.