0
votes

Puppet will contain all defined types declared inside another defined type (or class). As far as I understand, this implies that any declared source will depend on the container. This will result in a dependency loop:

define user {
}
define bar {
  user { $name: }
  ->
  Bar[$name]
}

bar { 'foo': }
Error: Could not apply complete catalog: Found 1 dependency cycle:
(User[foo] => Bar[foo] => User[foo])

Is there any way to avoid this? I ahve one specific instance where I would prefer that when Bar[$name] is declared, User[$name] be declared as well, but have Bar[$name] depend on User[$name], not the other way around. Basically the same behavior as require, but for a defined type dependency.

Is there any way to accomplish this or is the only solution to have the manifest declaring Bar[$name] declare User[$name] as well (and then add the dependency on either the body of bar or in the declaring manifest?


A more realistic example:

define servize {}
define appserver {
  user { $name: }
  ->
  servize { $name: }
}

appserver { 'app': }

# the deploy application needs a directory owned by itself on startup
file { '/tmp/foobar':
  ensure => directory,
  owner  => 'app', # auto-require
}
->
Appserver['app']
2
Does not quite compute. User[$name] is declared by Bar[$name], so what you really need is to have all resources declared by Bar[$name] that are not User[$name] to depend on User[$name], correct? Would it not be straight forward to express just that? - Felix Frank
@FelixFrank I already do that. But the dependency of user on appserver is still a problem. My example is a bit simplistic. Check my edit. In this case, you could break the loop by adding the dependency on Servize instead (and further break the abstraction...) but in more complex scenarios I sometimes still get loops from the service dependencies. It's simply unnecessary and undesirable to have user depend appserver. I wish that was a variant of create/ensure_resources that would create the resources and have them float in the graph (like classes). - Artefacto

2 Answers

1
votes

First of all, please do not redefine built-in types. List of all built-in types: https://docs.puppetlabs.com/references/latest/type.html.

If you have only one specific instance where $Bar[$name] depends on User[$name] you can remove user from bar definition and create ordered_bar

  define ordered_bar {
    user { $name: }
    ->
    bar {$name : }
  }

That you only need to create an instance of ordered_bar.
Please also read document about resource ordering in puppet: https://docs.puppetlabs.com/learning/ordering.html

0
votes

You can create the problematic resource as virtual. The feasability of this depends on the structure of your data layer.

define servize {}

user { 'app': }

define appserver {
  User<| title == $name |>
  ->
  servize { $name: }
}

appserver { 'app': }

# the deploy application needs a directory owned by itself on startup
file { '/tmp/foobar':
  ensure => directory,
  owner  => 'app', # still auto-require, but no ill effect
}
->
Appserver['app']