Virtual ressource in a define

240 views
Skip to first unread message

Sébastien Prud'homme

unread,
Jan 11, 2010, 7:03:25 AM1/11/10
to puppet-users
Hi,

I get a "duplicate definition problem" with Puppet 0.24.8 when using
virtual ressource in a define:

Here is a sample :

define mydefine1 {
@package { postfix: }
}

define mydefine2 {
mydefine1 { $name: }

realize Package[postfix]
}

mydefine2 { test1: }
mydefine2 { test2: }

Here is the problem:

Puppet::Parser::AST::Resource failed with error ArgumentError:
Duplicate definition: Package[postfix] is already defined in file
test.pp at line 2

If i move the virtual resource in a class all is working fine. For instance:

class common {
@package { postfix: }
}

define mydefine1 {
include common
}

define mydefine2 {
mydefine1 { $name: }

realize Package[postfix]
}

mydefine2 { test1: }
mydefine2 { test2: }

Does someone know if it's a bug or if i'm doing things the wrong way?

Thanks!

Silviu Paragina

unread,
Jan 11, 2010, 9:25:44 AM1/11/10
to puppet...@googlegroups.com
Each time a definition is "called" it defines all the resources. If the
definition for the virtual package isn't variable you should put it in a
class as classes get included only once. Otherwise you will have to
rename the resource depending on the variables of the definition
(doesn't seem the case here, because it is a package)

Ex:

class clspackage
{
@package { postfix: }
}

define mydefine1 {
include clspackage
}

define mydefine2 {
mydefine1 { $name: }

realize Package[postfix]
}


Silviu

jcbollinger

unread,
Jan 11, 2010, 2:29:26 PM1/11/10
to Puppet Users

On Jan 11, 6:03 am, Sébastien Prud'homme

<sebastien.prudho...@gmail.com> wrote:
> Does someone know if it's a bug or if i'm doing things the wrong way?

As Sliviu explained, you're doing things the wrong way. What he gave
you resolve your errors, but it is focused on how to get the virtual
package declaration to work. Depending on what you're trying to
accomplish, however, a virtual declaration may be a sub-optimal
approach to begin with.

I'm inferring that you want a define that may be called multiple
times, with every invocation needing to declare the same one resource
(among other things). In Puppet, you can achieve this directly with
classes -- involving virtual resources only complicates matters.
Thus, within the limited scope of the example, this solution will
achieve exactly the same result (effect of mydefine2) as Sliviu's
example:

class clspackage {
package { postfix: }
}

define mydefine1 {
include clspackage
}

define mydefine2 {
mydefine1 { $name: }
}

In general, although virtual resources seem cool, they don't do as
much as Puppet newcomers seem to think they do. I'm unaware of any
problem whose solution *requires* their use, and people seem inclined
to apply them to situations where they aren't helpful. YMMV.


John

Sébastien Prud'homme

unread,
Jan 11, 2010, 4:41:23 PM1/11/10
to puppet...@googlegroups.com
Thanks for the responses. My example is just an example. My real
"define" has some parameters so it's not possible to use a class.

Here is the same problem by another Puppet user:

http://www.mail-archive.com/puppet...@googlegroups.com/msg06262.html

2010/1/11 jcbollinger <John.Bo...@stjude.org>:

> --
> You received this message because you are subscribed to the Google Groups "Puppet Users" group.
> To post to this group, send email to puppet...@googlegroups.com.
> To unsubscribe from this group, send email to puppet-users...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
>
>
>
>

jcbollinger

unread,
Jan 12, 2010, 9:56:27 AM1/12/10
to Puppet Users

On Jan 11, 3:41 pm, Sébastien Prud'homme


<sebastien.prudho...@gmail.com> wrote:
> Thanks for the responses. My example is just an example. My real
> "define" has some parameters so it's not possible to use a class.

Whether 'mydefine1' has parameters is irrelevant to whether you can
achieve your configuration goal by putting the package declaration
into a class.

Are you trying to say that the parameters to 'mydefine1' are used to
set properties of the Package resource? That cannot work if
'mydefine1' is called more than once with different parameters.
Resources describe the desired state of the system, so it doesn't even
make sense to declare the same resource differently in different parts
of the same catalog. It is impossible to accommodate multiple
different specifications, because a resource can have only one state
at a time.

On the other hand, if the parameters for the package will be the same
every time 'mydefine1' is called within each given node's catalog,
then you definitely can put the package declaration (virtual or not)
into a class. You don't have to convert 'mydefine1' into a class, as
our examples show: you can put the package into an existing class if
there's a suitable one, or you can create a new class for it, as in
the example. It is still quite possible to customize the package's
parameters for each node.

You may need to rearrange your manifests more than you hoped before
they work, but there is no avoiding the prohibition against multiple
declarations of the same resource. We may be able to provide better
help if you are more specific about what you're trying to do.

Sébastien Prud'homme

unread,
Jan 12, 2010, 5:19:41 PM1/12/10
to puppet...@googlegroups.com
Hi,

The example is just there to show the duplicate problem that i don't
understand as i use a virtual ressource.

Here is another one:

define mydefine1 {
@file{ "/$name": ensure => directory }
}

define mydefine2($dir) {
mydefine1 { $dir: }

realize File["/$dir"]

file{ "/$dir/$name": ensure => directory }
}

mydefine2 { test1: dir => test}
mydefine2 { test2: dir => test}

I've got a lot of mydefine2 to declare. Sure a workaround would be to
add all the mydefine1 declarations in one single class and remove it
from mydefine2 but i find it's not an elegant solution.

2010/1/12 jcbollinger <John.Bo...@stjude.org>:

jcbollinger

unread,
Jan 13, 2010, 9:47:48 AM1/13/10
to Puppet Users

On Jan 12, 4:19 pm, Sébastien Prud'homme


<sebastien.prudho...@gmail.com> wrote:
> The example is just there to show the duplicate problem that i don't
> understand as i use a virtual ressource.

Each resource can be *declared* only once within any node's catalog,
no matter whether that declaration is concrete or virtual (or
exported). Virtual resources may be *realized* any number of times.
In your examples, multiple invocations of your "mydefine1" are
declaring the *same* (virtual) resource, hence Puppet complains.

A common usage model for virtual resources is to create a class
declaring all the virtual resources of a certain type that any of your
nodes might want, and then have different nodes realize the ones they
need. The canonical example seems to be system users; I believe the
best practices document describes that.

> define mydefine1 {
>  @file{ "/$name": ensure => directory }
> }

[...]


>  mydefine1 { $dir: }
>  realize File["/$dir"]

I see that pattern sometimes, and it is NEVER useful. Specifically,
it is not useful to declare a virtual resource and then immediately
realize it, for that is only a more complicated way of declaring a
concrete resource. Again, resource declarations may not be
duplicated, virtual or not. Only *realizations* may be duplicated.

> I've got a lot of mydefine2 to declare. Sure a workaround would be to
> add all the mydefine1 declarations in one single class and remove it
> from mydefine2 but i find it's not an elegant solution.

Sorry, no help for that. Personally, I would find it inelegant to
declare the same resource multiple times (even if the code were not
duplicated), so I'm not bothered in the slightest that Puppet
disallows it.

Suppose you moved the mydefine1 calls out of mydefine2 into whatever
class contains all the mydefine2 calls? That still keeps it nicely
packaged together:

class somefiles {
define mydefine1 {
...
}

define mydefine2($dir) {
...
}

mydefine1 {"dir1": }
mydefine2 { "test1": dir => "dir1" }
mydefine2 { "test2": dir => "dir1" }

mydefine1 {"dir2": }
mydefine2 { "test3": dir => "dir2" }
mydefine2 { "test4": dir => "dir2" }
}

YMMV, but I don't see anything inelegant about that.


John

jcbollinger

unread,
Jan 13, 2010, 9:53:37 AM1/13/10
to Puppet Users

On Jan 13, 8:47 am, jcbollinger <John.Bollin...@stJude.org> wrote:
> YMMV, but I don't see anything inelegant about that.

Note also that you can then simplify your definitions by making the
virtual file declaration concrete and removing the realize() call.
You might even be able to remove the "dir" parameter to mydefine2.
Surely simpler code contributes to elegance.


John

Sébastien Prud'homme

unread,
Jan 13, 2010, 5:22:52 PM1/13/10
to puppet...@googlegroups.com
Ok, thanks for all your explanations. I didn't noticed the virtual
ressource was declared twice...

Thanks a lot again.

2010/1/13 jcbollinger <John.Bo...@stjude.org>:

Reply all
Reply to author
Forward
0 new messages