Call call multiple times

94 views
Skip to first unread message

Juliano Resende

unread,
Sep 3, 2014, 2:09:38 PM9/3/14
to puppet...@googlegroups.com
Hi Folks,

I have a doubt about call classes multiple times, i write a module to manage FTP users, but i can create only one user, because when i call the a second time i receive a error about duplicate instance

My Module

define vsftpd::manager (
    $user,
    $docroot = '/var/www',
    $conf = '/etc/vsftpd',
){
    include vsftpd
    user { "$user":
         ensure => present,
         shell => "/bin/false",
         home => "${docroot}/${user}",
         gid => 480,
  }

 file { "${conf}/user_list":
         ensure => present,
 }
 file_line { 'ftp_user':
         line => $user,
         path => "${conf}/user_list",
 }
}

node.pp

node 'puppetclient' {
      vsftpd::manager{'teste':
      user => 'teste',
 }
}

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Duplicate declaration: File[/etc/vsftpd/user_list] is already declared in file /etc/puppet/environments/production/modules/vsftpd/manifests/manager.pp:16; 

Somebody can help me?

jcbollinger

unread,
Sep 4, 2014, 11:51:24 AM9/4/14
to puppet...@googlegroups.com


On Wednesday, September 3, 2014 1:09:38 PM UTC-5, Juliano Resende wrote:
Hi Folks,

I have a doubt about call classes multiple times, i write a module to manage FTP users, but i can create only one user, because when i call the a second time i receive a error about duplicate instance



You will help yourself if you stop imagining that you are "calling" classes and defined types.  They are not executable in the sense that you have in mind, and supposing that they are tends to lead people to have the wrong expectations.  Puppet is not a script engine.

 
My Module



What follows is not a "module" (nor a class, either) in the sense that term is used in Puppet jargon.  It is a defined resource type, which appears to be part of a module named "vsftpd".  Whether it is in fact part of such a module depends on where the manifest file containing it is located.

Please forgive me for being picky about terminology, but effective communication depends on agreeing on the meanings of the words we use, and already Puppet presents more than the usual number of challenges in that area.

 
define vsftpd::manager (
    $user,
    $docroot = '/var/www',
    $conf = '/etc/vsftpd',
){


It looks like your type represents an FTP user.  As such, "vsftpd::manager" is an awfully strange name for it.  I recommend you name your classes and types to describe the things they represent on the target system, so in this case maybe "vsftpd::user".

Moreover, regardless of the type's name, instances are all about the user name currently expressed via $user parameter.  Is there a reason to not reflect that by expressing the user via the resource title (which you're not now using for anything)?

 
    include vsftpd
    user { "$user":
         ensure => present,
         shell => "/bin/false",
         home => "${docroot}/${user}",
         gid => 480,
  }


This is part of your problem:
 
 file { "${conf}/user_list":
         ensure => present,
 }


You may not declare the same resource multiple times.  Supposing that multiple users can be registered with the same VSFTP installation, the user_list file does not belong to any one user, therefore it should be factored out of this definition.  Unless you anticipate needing multiple, separate VSFTP configurations on the same machine, this resource could conceivably be moved to your "vsftpd" class.  In that case, it probably doesn't make sense to keep the 'conf' parameter to the current definition, because you would always want to use the same one used by class vsftpd.

You also have a problem with the next declaration:
 
 file_line { 'ftp_user':
         line => $user,
         path => "${conf}/user_list",
 }


This one is easier.  Every resource must have a unique title among resources of its type.  Your file_line is properly specific to an instance of the enclosing type; it just needs a unique title.


Putting it all together, you might get something like this:

define vsftpd::user (
    $docroot = '/var/www'
){
  include vsftpd

  user { $title:
         ensure => present,
         shell => '/bin/false',
         home => "${docroot}/${title}",
         gid => 480,
  }

  file_line { "ftp_user_${title}":
         line => $user,
         # supposes the correct user_list is recorded
         # in a class variable of class "vsftpd":
         path => $vsftpd::user_list
  }
}



John

Reply all
Reply to author
Forward
0 new messages