Help with Multiple Resource Declarations

43 views
Skip to first unread message

Daniel Kinon

unread,
May 3, 2019, 12:21:35 PM5/3/19
to puppet...@googlegroups.com
Hello Everyone,
    So I'm trying to create templates for system users.  Here is my systemusers class:
~~~
class base::systemusers (
  $username = $title,
  $home     = "/var/lib/$username",
) {
  $systemusers   = lookup({ name => 'base::systemusers' })
  user { $username:
    ensure     => present,
    system     => true,
    uid        => $systemusers[$username]['uid'],
    home       => $home,
    managehome => true,
    shell      => '/bin/bash',
  }

  file { "$home/.ssh":
    ensure  => directory,
    owner   => $username,
    group   => $username,
    mode    => '0700',
  }

  file { "/var/run/$username":
    ensure  => directory,
    owner   => $username,
    group   => $username,
    mode    => '0755',
  }

  file { "/var/log/$username":
    ensure  => directory,
    owner   => $username,
    group   => $username,
    mode    => '0755',
  }
~~~

This works great when I only have 1 system user but the minute I have more than 1 I get a Duplicate declaration: Class[Base::Systemusers] error.  I've looked at the docs for virtual resources (tbh, it breaks my brain a little) but all the examples seem to be for general resources and not classes.  I've tried a bunch of different iterations to solve this and I haven't gotten any of them to work.  If someone could point me in the right direction, I'd appreciate it.

Thanks,
-Dan

Stephen Marlow

unread,
May 3, 2019, 1:14:35 PM5/3/19
to puppet...@googlegroups.com
Hey Dan,

  The error you're getting is just saying that you've declared the Base::Systemusers class twice and a class can only be declared once. I suspect that your code looks something like this:

  $systemusers   = lookup({ name => 'base::systemusers' })
  $systemusers.each |$username, $userinfo| {
    class { 'base::systemusers':
      username => $username,
    }
  }

  If that is the case then you should be able to fix the problem by changing Base::Systemusers from a class to a define. Defined types can be declared multiple times as long as each one has a unique title. You can find more information about defined types here: https://puppet.com/docs/puppet/6.4/lang_defined_types.html

  The syntax to declare the defined type would change slightly. It should look like this:
  base::systemusers { $username: }

  Let me know if you have any questions (or if I guess incorrectly about what your code looks like).

  - Steve

--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/CAMGSraH5Sn31xPt8Z4DN8Xj74g20TZZ4z%3DPgD5TwgP%3DtWRT%3DxQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Daniel Kinon

unread,
May 4, 2019, 6:29:53 PM5/4/19
to puppet...@googlegroups.com
Hey Stephen and all,
    You are correct in your assumptions, and this definitely solved my problem.  I tried going down this path before but only met failure, looks like my declaration syntax might have been wrong and I might have also had issues with the define syntax itself but I'm unsure at this point.  Most importantly, it works!

    So now that this is working, will it also work if I have multiple different manifests declaring the same resource?  I'm trying to use the concept of roles so that I can assign one to many roles to each host.  So lets assume the username is testing.  If I have role1.pp declare `base::systemusers { testing: }` and role2.pp also declares the same user, I'm assuming that will also create a resource duplication.  If that assumption is incorrect then I'm good, otherwise I'm not sure how to solve that issue.  I've read up on virtual resources and I think I understand how the declaration works however I'm unsure where to collect/realize that resource.
Thanks,
-Dan

jcbollinger

unread,
May 6, 2019, 9:19:28 AM5/6/19
to Puppet Users


On Friday, May 3, 2019 at 12:14:35 PM UTC-5, Stephen Marlow wrote:
Hey Dan,

  The error you're getting is just saying that you've declared the Base::Systemusers class twice and a class can only be declared once.


No, not exactly. Puppet's diagnostic is deceiving here: classes may be declared any number of times, BUT only the first declaration evaluated may have the resource-like form, e.g.

class { 'base::systemusers': }

This is and always has been an excellent reason to avoid using resource-like declarations, of modules' public classes, though with care, you may use them inside a module for that module's private classes.  Elsewhere, use include-like declarations instead:

include 'base::systemusers'

... and rely on automatic data binding for any needed parameter customization.

However, classes are idempotent.  Declaring the same class multiple times (in one of the allowed ways) has the same effect as declaring it just once.  That is in fact one of the reasons why only the first-evaluated declaration of a given class may take the resource-like form.

 
  If that is the case then you should be able to fix the problem by changing Base::Systemusers from a class to a define.


Yes, the OP appears to want a defined type here, not a class, because they appear specifically to want non-idempotency.  This goes straight to the difference between classes and defined types.


John

jcbollinger

unread,
May 6, 2019, 9:38:17 AM5/6/19
to Puppet Users


On Saturday, May 4, 2019 at 5:29:53 PM UTC-5, Daniel Kinon wrote:
Hey Stephen and all,
    You are correct in your assumptions, and this definitely solved my problem.  I tried going down this path before but only met failure, looks like my declaration syntax might have been wrong and I might have also had issues with the define syntax itself but I'm unsure at this point.  Most importantly, it works!

    So now that this is working, will it also work if I have multiple different manifests declaring the same resource?


No.  Defined resource types are resource types like any other.  You may not declare duplicate resources of any type.

 
  I'm trying to use the concept of roles so that I can assign one to many roles to each host.  So lets assume the username is testing.  If I have role1.pp declare `base::systemusers { testing: }` and role2.pp also declares the same user, I'm assuming that will also create a resource duplication.


Yes, it will.

 
  If that assumption is incorrect then I'm good, otherwise I'm not sure how to solve that issue.  I've read up on virtual resources and I think I understand how the declaration works however I'm unsure where to collect/realize that resource.


Virtual resources are one way to approach this problem.  The setup could go something like this:

  • There is one class that declares all the virtual base::systemuser resources that are used by any system under management, say base::privileged_users.
  • Each role class includes class base::privileged_users (remember that classes may be declared as many times as desired with include-like declarations)
  • Each role class realizes the base::systemuser resources it requires.
But really, these days the emphasis and recommendation is to push configuration details out of manifests into external data (which dovetails nicely with automated data binding and include-like class declarations).  Going this way opens up a great expanse of possibilities to either avoid duplication in the first place or to resolve it in Puppet code, prior to declaring anything.  For example, you could
  • externalize the user details with which you would parameterize base::systemuser resources
  • externalize mappings between roles and sets of users
  • externalize the set of roles each node has
  • provide a class that determines which system users are required by merging the user lists from all of the target node's roles, and declares all the wanted base::systemuser resources based on the external data

One of the advantages of going this route is that when you want to change user details or user - role mappings, you only need to modify your data, not your manifests.


John

Reply all
Reply to author
Forward
0 new messages