Re: [Puppet Users] package handling in puppet?

183 views
Skip to first unread message

Craig White

unread,
Aug 21, 2012, 1:22:24 PM8/21/12
to puppet...@googlegroups.com

On Aug 21, 2012, at 9:05 AM, lamour wrote:

> I'm starting to feel like, maybe, I have a fundamentally flawed concept of how puppet is intended to be used. (new to puppet. setting up initial puppet environment. blah blah)
>
> so, I've got most of the pieces worked out, but I've hit a major roadblock with the way packages are handled in puppet. (according to my limited understanding of puppet, that is) The problem starts with the fact that including the following in two different classes:
>
> package { 'perl': ensure => installed }
>
> causes this error:
>
> "Duplicate definition: Package[perl] is already defined"
>
> This is pretty unfortunate, but we can try to work around it by doing this:
>
> package { 'test-perl': ensure => installed, alias => 'perl' }
>
> which gives us this error:
>
> "Parameter alias failed: test-perl can not create alias perl: object already exists"
>
> Ok, can't even get around it like that. I've found two ways around this so far, both are kinda gross, so I'm starting to wonder if I'm working against some "prime directive" of puppet.
----
if you have packages that are pre-requisites for more than one other package, create a separate class and include the class where desired. Done.
----
>
> One pretty kludgey way around it is to wrap each package definition in a class and then just "include" the classes where I want the packages defined. I mean, I can write a perl script to generate a class for each package that is in my packaging system and just do it this way, but it just feels like I'm cheating, and I have no idea what kind of overhead that would put on puppet.
>
> Another, less gross, way to do it is to do something like this:
>
> if !defined(Package['perl']) {
> package { 'perl':
> ensure => installed,
> }
> }
>
> This is kinda what I expected "ensure => installed" to mean. The big problem with this method is that it's so verbose that to do this for every package I want to include would make it somewhat difficult to see which packages I was including in a class if I had more than a few. I can fix a bit of the bulkiness by reformatting the expression, but it's still pretty verbose. The obvious answer to this mess is a defined type, and yet, using a simple defined type brings us full circle to collisions again. lol (yes, I can create a defined type that avoids the collision, but then the invocation starts to get pretty verbose again, and really, it just starts to feel like I'm not doing any of this "the right way")
>
> We also stumbled across the Singleton puppet module, which does almost kind of exactly what we want, except it has a dependency on hiera. We haven't really decided whether to use hiera or not. Efforts to rip the hiera dependencies out of Singleton and also getting it to run even with hiera installed have both failed. I'll probably keep looking into modifying the ruby code to behave in some useful manner for us, but for now, I'm running out of good options.
>
> So...what am I doing wrong? Does the puppet philosophy not really allow for maintaining package lists in classes? Do people pretty much define classes down at the host level to get around this limitation? Does everyone use some external DB or something to track which classes require which packages and just manually avoid the collision problem? Is there some magic syntax that I just haven't found yet? Am I just totally on the wrong track?
>
> To describe what I'm trying to accomplish, I have a "baseline" class which defines things I want everywhere and I want to be able to define classes like "mail_server", "web_server", "samba_server", etc, and then just include whichever of those classes on a box I need to define the machine's configuration. I think I've figured out how to do every piece of this except the packages. I saved this until last, because, honestly, I never imagined that it was going to work this way. sigh
----
Hiera will be part and parcel of puppet 3 so you would be better off designing to live with it rather than try to force life without it long term.

I'm sort of suspicious that you are trying to use Singleton as a means to avoid a full implementation of puppet. It seems that trying to shortcut understanding of puppet leads to frustration.

Craig

lamour

unread,
Aug 21, 2012, 3:44:53 PM8/21/12
to puppet...@googlegroups.com

On Tuesday, August 21, 2012 1:22:24 PM UTC-4, Craig White wrote:

----
if you have packages that are pre-requisites for more than one other package, create a separate class and include the class where desired. Done.
----

Ok, I'm just making sure that I understand what you're saying.  Are you saying that the proper way to handle packages in puppet is to manage the packages required by my classes with the built in package resource type and whenever puppet pitches errors because of a package collision, to add a class that wraps that package resource definition and then change the manifests to include the class instead of defining the package directly?  I guess I must not understand what you mean, because that doesn't sound particularly desirable to me.

 

----
Hiera will be part and parcel of puppet 3 so you would be better off designing to live with it rather than try to force life without it long term.


Ok, this is good to know.  I guess I'll read up more on it.  Thanks.


 
I'm sort of suspicious that you are trying to use Singleton as a means to avoid a full implementation of puppet. It seems that trying to shortcut understanding of puppet leads to frustration.


I'm not sure what I said that led you to believe this is what I'm doing.  I'm asking for advice as to what the "correct" way to handle this in puppet is.  I laid out all the ways I've come up with to (try to) deal with my problem.  What I don't know is why this isn't easier.  It makes me feel like I'm doing it all wrong.  And I'm not sure what you mean by "full implementation".  You mean, without hiera?  Or is there something else fundamentally wrong with what I'm doing?


Honestly, we've barely started with our implementation of puppet.  In our test environment, we have working classes for a few services and have a loose framework in place that handles some of the thornier issues of our environment.  We've read a lot of docs, added parser functions, added custom facter facts, added custom augeas lenses, etc.  I've found simple, fairly elegant ways to deal with almost everything I've tried to do in puppet.  I'm just feeling that maybe I'm missing the big picture or maybe, at least, A big picture.


I'm not trying to work around anything.  I'm just trying to figure out the best way to use puppet to manage my hosts in a way that is easy to understand, audit and maintain.  I'm sorry that wasn't clear from my original post.  I guess I feel that I'm starting to understand some of the knobs in puppet, but I maybe don't understand the plan.  That's why I came here.  I hoped someone here had a better understanding of the big picture (or a simple solution to my current problem).



thanks for your help,

Michael

 

Ramin K

unread,
Aug 21, 2012, 3:57:43 PM8/21/12
to puppet...@googlegroups.com
On 8/21/2012 9:05 AM, lamour wrote:
> I'm starting to feel like, maybe, I have a fundamentally flawed concept
> of how puppet is intended to be used. (new to puppet. setting up
> initial puppet environment. blah blah)
>
> so, I've got most of the pieces worked out, but I've hit a major
> roadblock with the way packages are handled in puppet. (according to my
> limited understanding of puppet, that is) The problem starts with the
> fact that including the following in two different classes:
>
> package { 'perl': ensure => installed }
>
> causes this error:
>
> "Duplicate definition: Package[perl] is already defined"
>
> This is pretty unfortunate, but we can try to work around it by doing this:
>
> package { 'test-perl': ensure => installed, alias => 'perl' }
>
> which gives us this error:
>
> "Parameter alias failed: test-perl can not create alias perl: object
> already exists"
>
> Ok, can't even get around it like that. I've found two ways around this
> so far, both are kinda gross, so I'm starting to wonder if I'm working
> against some "prime directive" of puppet.

What happens when you have two or more statements about the same
resource in conflict?

package { 'mysql': ensure => installed, }
package { 'mysql': ensure => 5.0.92, }
package { 'mysql': ensure => latest, }

Therefore you need to specify it once. You can do this a few different
ways.

class perl {
package { 'perl': ensure => installed }
}

class someclass {
include perl
file { 'somefile': content => 'stuff', require => Class['perl',}
}

or going in a different direction

class virtualpackages {
@package { 'perl': }
}

class someclass {
include perl
file { 'somefile': content => 'stuff', require => Package['perl',}

realize Package['perl']
}

Personally I find it simpler to use the first method for most complex
things and the later for one off packages that might be needed for
multiple things like mysql-client libs.

Ramin

Tim Mooney

unread,
Aug 21, 2012, 6:25:53 PM8/21/12
to puppet...@googlegroups.com
In regard to: [Puppet Users] package handling in puppet?, lamour said (at...:

> I'm starting to feel like, maybe, I have a fundamentally flawed concept of
> how puppet is intended to be used. (new to puppet. setting up initial
> puppet environment. blah blah)
>
> so, I've got most of the pieces worked out, but I've hit a major roadblock
> with the way packages are handled in puppet. (according to my limited
> understanding of puppet, that is) The problem starts with the fact that
> including the following in two different classes:
>
> package { 'perl': ensure => installed }

There are several ways to deal with this.

I know perl is probably a general example of the problem, but at least
in that case, it's fairly rare that you need to specify the interpreter
directly. If you're making good use of packages, what you probably
instead want is something like

package { 'perl-Net-SMTP-SSL':
ensure => installed,
require => Yumrepo['your-local-repo-name-or-maybe-epel'],
}

In other words, specify your "package { whatever: }" so that it asks
for the "highest level" requirement, and just let the packaging system
pull in the dependencies. A properly packaged perl module should
automatically cause perl to be installed.

Let's say you have an unpackaged script (hint: consider packaging it!)
that relies on just the core perl modules and doesn't have any external
module dependency that you can key on, so keying on some higher level
dependency isn't going to work.

Now you're back to the cases you were considering.

For the first case:

> causes this error:
>
> "Duplicate definition: Package[perl] is already defined"
>
> This is pretty unfortunate, but we can try to work around it by doing this:
>
> package { 'test-perl': ensure => installed, alias => 'perl' }

*Definitely* do not do this. There might be other places where this
kind of chicanery is appropriate, but it's not a good idea here.

> One pretty kludgey way around it is to wrap each package definition in a
> class and then just "include" the classes where I want the packages
> defined.

That's the way we do it for packages where we've run into this issue, but
remember again that you generally don't need to do this for every package,
you just need to do it for cases where you can identify a package that
must be installed *but* isn't going to be pulled in automatically by your
package management system via a dependency from some *other* package
you're requiring.

> I mean, I can write a perl script to generate a class for each
> package that is in my packaging system and just do it this way, but it just
> feels like I'm cheating, and I have no idea what kind of overhead that
> would put on puppet.

I wouldn't recommend that. Generate only the classes that you need, and
consider subclasses too. For example, we do have a few cases where
non-packaged scripts written by e.g. a dba require something like perl's
Foo::Bar module. We have a class for perl and subsclasses for stuff like
perl::foo::bar. We only need to

include perl::foo::bar

and that has the

package { 'perl-Foo-Bar':
ensure => installed,
}

*and* the actual OS package has the proper dependency to get pulled
in if needed.

> Another, less gross, way to do it is to do something like this:
>
> if !defined(Package['perl']) {
> package { 'perl':
> ensure => installed,
> }
> }

I would instead do something more like

file { 'your-unpackaged-perl-script-here.pl':
ensure => file,
owner => 'whomever',
group => 'ditto',
mode => '0whatever-whatever-whatever',
require => Package['perl'],
source => 'puppet:///module_name/script-source-here.pl',
}

> This is kinda what I expected "ensure => installed" to mean. The big
> problem with this method is that it's so verbose that to do this for every
> package I want to include would make it somewhat difficult to see which
> packages I was including in a class if I had more than a few.

So do

class your_class {

include your_class::packages

# other stuff here.

}

and split your packages into the your_class::packages class.

> We also stumbled across the Singleton puppet module, which does almost kind
> of exactly what we want, except it has a dependency on hiera. We haven't
> really decided whether to use hiera or not. Efforts to rip the hiera
> dependencies out of Singleton and also getting it to run even with hiera
> installed have both failed. I'll probably keep looking into modifying the
> ruby code to behave in some useful manner for us, but for now, I'm running
> out of good options.

Don't rip out hiera, it will be part of puppet 3.x. I'm not familiar with
the Singleton module, but I wouldn't think you would need to resort to
external modules for something that's pretty fundamental to the problem
domain.

Another option that some have used in this situation is virtual resources
for packages, e.g.

class all_packages {

@package { 'perl': }
@package { 'perl-Foo-Bar': }

}

and

class your_class {

realize(Package['perl-Foo-Bar'])

}

That might be worth considering. We're not doing it that way, but
perhaps we should be.

> So...what am I doing wrong? Does the puppet philosophy not really allow
> for maintaining package lists in classes?

It does, but in my experience it should be done in a minimal fashion.
Specify the highest level dependency, and let the OS package management
system pull in the prereqs, rather than trying to repeat all of the same
relationships in your puppet classes.

Tim
--
Tim Mooney Tim.M...@ndsu.edu
Enterprise Computing & Infrastructure 701-231-1076 (Voice)
Room 242-J6, IACC Building 701-231-8541 (Fax)
North Dakota State University, Fargo, ND 58105-5164

lamour

unread,
Aug 22, 2012, 12:55:28 PM8/22/12
to puppet...@googlegroups.com, ramin...@badapple.net


On Tuesday, August 21, 2012 3:57:43 PM UTC-4, Ramin K wrote:

        What happens when you have two or more statements about the same
resource in conflict?

  package { 'mysql': ensure => installed, }
  package { 'mysql': ensure => 5.0.92, }
  package { 'mysql': ensure => latest, }
 
Ok, I think this is my issue.  To me, "installed" doesn't sound like it should conflict with the other two at all.  It sounds like "hey, I don't care which version of mysql you have, as long as you have one. If not...let's fix that now."  But that's not what it means.  If it did, then puppet wouldn't need to flag it as a collision if I wrote this:

  package { 'mysql': ensure => installed, } 
  package { 'mysql': ensure => installed, } 
  package { 'mysql': ensure => installed, } 

Puppet would be able to say "check if it's installed.  yep, we're checking if it's installed.  yep, we're checking if it's installed."

And, if you think about it, this wouldn't even be a problem (logically speaking):

  package { 'mysql': ensure => installed, } 
  package { 'mysql': ensure => 5.0.92, } 
  package { 'mysql': ensure => installed, } 

But I just need to let that go, since puppet doesn't work that way.  lol


Anyway, we've decided to go with the !Defined syntax I suggested in my original post for now until we find a better solution, since that syntax actual means what we mean, and doesn't require external logistics.  We'll revisit this decision after we've gotten more classes implemented and evaluate the relative benefits of the other available solutions at the time.  This will at least allow us to move forward and get other things working.


Therefore you need to specify it once. You can do this a few different
ways.

 
[examples for virtual resources and classes deleted]

So, my basic issue with both the class method and the virtual resources method is that they basically require me to maintain a SECOND list of every package I want to maintain this way (either class or virtual resource definitions).  This seems like a lot of syntactic and logistical overhead, especially when you consider that if we ignore the possibility of collisions, we can just do this:

package { ['perl', 'mysql', 'gcc', 'screen', 'foo', 'bar', 'baz']:
    ensure => installed
}

This is clean, concise, and trivial to understand.  This is kind of what I was hoping for.  I understand that we'll probably have to use the class method for any packages where ACTUAL conflicts exist (e.g., the version example you gave above), but for virtually all of our packages, we're not going to have that problem.


Thanks a lot for your feedback.  It was good to have simple examples of all the options in one place.


thanks,
Michael

lamour

unread,
Aug 22, 2012, 3:40:49 PM8/22/12
to puppet...@googlegroups.com, tim.m...@ndsu.edu


On Tuesday, August 21, 2012 6:25:53 PM UTC-4, Tim Mooney wrote:
In regard to: [Puppet Users] package handling in puppet?, lamour said (at...:

> so, I've got most of the pieces worked out, but I've hit a major roadblock
> with the way packages are handled in puppet.  (according to my limited
> understanding of puppet, that is)  The problem starts with the fact that
> including the following in two different classes:
>
>   package { 'perl': ensure => installed }

There are several ways to deal with this.

I know perl is probably a general example of the problem, but at least
in that case, it's fairly rare that you need to specify the interpreter
directly.  If you're making good use of packages, what you probably
instead want is something like

   package { 'perl-Net-SMTP-SSL':
     ensure  => installed,
     require => Yumrepo['your-local-repo-name-or-maybe-epel'],
   }


Yeah, that's what we're planning on doing, but that only gets you so far.  The real issue with all of this is that I don't want the act of someone adding a package into a class somewhere to cause puppet to fail due to an unexpected collision.  If I want to avoid that, I need to use some syntax that doesn't flag conflicts where they don't actually exist.  For instance, I might require perl-DBI in, say, the samba class and the apache class (for whatever reason).  There's not really a problem with that unless I need both of those classes on the same server.  This leaves me with two choices, allow the errors to happen and fix them as they pop up or just pre-wrap every package in a class to avoid the problem altogether.  Both choices make me sad.  lol

 
> This is pretty unfortunate, but we can try to work around it by doing this:
>
>   package { 'test-perl': ensure => installed, alias => 'perl' }

*Definitely* do not do this.  There might be other places where this
kind of chicanery is appropriate, but it's not a good idea here.

 
Ok.  lol.  I probably wouldn't have implemented it this way anyway, but it was the first work-around that I thought of when we ran into the problem.

 
> Another, less gross, way to do it is to do something like this: 
>
>       if !defined(Package['perl']) {
>          package { 'perl':
>             ensure => installed,
>          }
>       }

I would instead do something more like

   file { 'your-unpackaged-perl-script-here.pl':
     ensure  => file,
     owner   => 'whomever',
     group   => 'ditto',
     mode    => '0whatever-whatever-whatever',
     require => Package['perl'],
     source  => 'puppet:///module_name/script-source-here.pl',
   }


So, I guess I don't understand this.  Does this require not cause a collision?  Does this require cause the resource to become defined?  Can you require more than one package?  I'll have to go read the documentation to learn more about what this does, even though I don't think this helps me, because I can't see how I could realistically tie all of my package definitions to files.

 
> We also stumbled across the Singleton puppet module, which does almost kind
> of exactly what we want, except it has a dependency on hiera. We haven't
> really decided whether to use hiera or not.  Efforts to rip the hiera
> dependencies out of Singleton and also getting it to run even with hiera
> installed have both failed.  I'll probably keep looking into modifying the
> ruby code to behave in some useful manner for us, but for now, I'm running
> out of good options.

Don't rip out hiera, it will be part of puppet 3.x.  I'm not familiar with
the Singleton module, but I wouldn't think you would need to resort to
external modules for something that's pretty fundamental to the problem
domain.


Yeah, looking at the documentation again, it seems like I misunderstood how Singleton works.  It seems like the configuration for the Singleton package is even more involved than the other options we've discussed here, which kinda defeats the purpose.  I think I could probably figure out a way to make a function to do what I want, but I'm going to save it for when I get a little more comfortable with ruby.  lol


Thanks for all of your advice.  It's nice to get a bit of perspective from people who are already using puppet in the wild.


thanks,
Michael

Tim Mooney

unread,
Aug 22, 2012, 3:59:16 PM8/22/12
to puppet...@googlegroups.com
In regard to: Re: [Puppet Users] package handling in puppet?, lamour said...:

>>> Another, less gross, way to do it is to do something like this:
>>
>>
>>> if !defined(Package['perl']) {
>>> package { 'perl':
>>> ensure => installed,
>>> }
>>> }
>>
>> I would instead do something more like
>>
>> file { 'your-unpackaged-perl-script-here.pl':
>> ensure => file,
>> owner => 'whomever',
>> group => 'ditto',
>> mode => '0whatever-whatever-whatever',
>> require => Package['perl'],
>> source => 'puppet:///module_name/script-source-here.pl',
>> }
>>
>>
> So, I guess I don't understand this. Does this require not cause a
> collision?

The answer is, "it depends". I didn't include everything I should have
in that example, because you *still* need to have a

package { 'perl': }

somewhere *and* that needs to be either included from some other class
or it needs to be established in the same manifest.

> Does this require cause the resource to become defined?

No it does not, that still has to happen elsewhere.

> Can
> you require more than one package?

Yes, and you can have multiple different resources that require the
same resource, e.g.

package { 'cricket':
ensure => installed,
require => [
Yumrepo['ndsu'],
Package['httpd', 'pmacct'],
User['cricket'],
],
}

package { 'flow-utils':
ensure => installed,
require => [
User['cricket'],
Mount['/var/netflow'],
],
}

> I'll have to go read the documentation
> to learn more about what this does, even though I don't think this helps
> me, because I can't see how I could realistically tie all of my package
> definitions to files.

My example was really meant for the case where you have one-off scripts
that are *not* installed via the OS package management system. As I said
before, you generally want to let the OS package management system handle
the dependencies as much as possible.

One more thing: if you search the archives, I think you'll find that
although "defined()" has its uses, it seems like the general feeling is
that it's somewhat overused, and used in cases where it really was not
intended. Your use of defined() might be perfect, but I just tend to shy
away from defined(), probably because my knowledge of puppet doesn't make
me certain that I would use it in the appropriate cases.

> Thanks for all of your advice. It's nice to get a bit of perspective from
> people who are already using puppet in the wild.

I'm hoping that other more experienced puppet users will weigh in on this
too, as I certainly am not expert enough yet to have all the answers for
this particular area.

Ramin K

unread,
Aug 22, 2012, 5:06:41 PM8/22/12
to puppet...@googlegroups.com
On 8/22/2012 9:55 AM, lamour wrote:

> So, my basic issue with both the class method and the virtual resources
> method is that they basically require me to maintain a SECOND list of
> every package I want to maintain this way (either class or virtual
> resource definitions). This seems like a lot of syntactic and
> logistical overhead, especially when you consider that if we ignore the
> possibility of collisions, we can just do this:
>
> package { ['perl', 'mysql', 'gcc', 'screen', 'foo', 'bar', 'baz']:
> ensure => installed
> }
>
> This is clean, concise, and trivial to understand. This is kind of what
> I was hoping for. I understand that we'll probably have to use the
> class method for any packages where ACTUAL conflicts exist (e.g., the
> version example you gave above), but for virtually all of our packages,
> we're not going to have that problem

I'd argue that you're trying to bring your procedural shell scripting
world into Puppet. :-) It's the difference between wanting to
micromanage the control you have of a system vs giving Puppet the power
to affect the control you want. Let's consider some of the packages
you've listed above.

My Mysql module and templates are 200 lines which install and configure
mysql-server, supports three distros, sets various variables based on
local facts, and uses Hiera to manage other settings based on the role
of the server. Installing the package is actually the simplest thing it
does.

In the case of gcc it's part of a modules called general_devel which
installs gcc, make, zlib, etc. I don't recall a situation where I would
need to install gcc without support packages so again installing gcc is
the simplest thing it does. Supports three distros, 30 lines.

Screen is part of the base node and I use a vpackage module and realize
it along with vim, htop, etc. Perl is installed by default so I don't
have it anywhere, but I'd probably put it here or make a module for it
so I could install any support tools and libs there.

So your example in my world ends up looking like the following code. On
the surface it's more complicated, but in application to a node it's
actually simpler in my opinion because I have easy entry points to the
complexity I've delegated to the modules. This allows me to drop
discrete packages of capabilities on to servers without having to
revisit the internal logic every time. include mysql does this for me,
package { 'mysql': ensure => present,} does not.

Ramin

node 'some.node.my.domain.com inherits basenode {
include mysql
include general_devel
realize Package['mysql-client']
}

node basenode {
include sudo
include vpackage

# realize all packages with this tag
Package<| tag = 'utils' |>
}

class vpackage {

# packages with tag => util get realized on all systems
@package { 'curl': tag => 'utils',}
@package { 'htop': tag => 'utils',}
@package { 'lynx': tag => 'utils',}
@package { 'screen': tag => 'utils',}
@package { 'strace': tag => 'utils',}
@package { 'tcpdump': tag => 'utils',}
@package { 'wget': tag => 'utils',}
@package { 'whois': tag => 'utils', name =>
$vpackages::params::whois, }

@package { 'mysql-client': name => $vpackages::params::mysqlclient, }
}

lamour

unread,
Aug 24, 2012, 4:38:54 PM8/24/12
to puppet...@googlegroups.com, ramin...@badapple.net

On Wednesday, August 22, 2012 5:06:41 PM UTC-4, Ramin K wrote:
On 8/22/2012 9:55 AM, lamour wrote:

> So, my basic issue with both the class method and the virtual resources
> method is that they basically require me to maintain a SECOND list of
> every package I want to maintain this way (either class or virtual
> resource definitions).  This seems like a lot of syntactic and
> logistical overhead, especially when you consider that if we ignore the
> possibility of collisions, we can just do this:
>
> package { ['perl', 'mysql', 'gcc', 'screen', 'foo', 'bar', 'baz']:
>      ensure => installed
> }
>
> This is clean, concise, and trivial to understand.  This is kind of what
> I was hoping for.  I understand that we'll probably have to use the
> class method for any packages where ACTUAL conflicts exist (e.g., the
> version example you gave above), but for virtually all of our packages,
> we're not going to have that problem

        I'd argue that you're trying to bring your procedural shell scripting
world into Puppet. :-)

I'm positive that this is the case.  lol.  But really, a big part of it is that I just
want class definitions to be easy to read, audit, and maintain, and if I have to
maintain a list of all packages in multiple places, that's going to break on a
live network.  People are people.  Someone's going to forget something.  The
lists are going to get out of sync.  Things will break.  It'll be a mess.
 

        My Mysql module and templates are 200 lines which install and configure
mysql-server, supports three distros, sets various variables based on
local facts, and uses Hiera to manage other settings based on the role
of the server. Installing the package is actually the simplest thing it
does.

Yeah, my Samba module is well over 100 lines long and does some pretty nifty
things.  I'm sure there will be other packages which will similarly require special
care and feeding.  However, I'd expect the bulk of my packages to simply need
to be itemized in someway.  No special care and feeding required.

 
So your example in my world ends up looking like the following code. On 
the surface it's more complicated, but in application to a node it's
actually simpler in my opinion because I have easy entry points to the
complexity I've delegated to the modules. This allows me to drop
discrete packages of capabilities on to servers without having to
revisit the internal logic every time. include mysql does this for me,
package { 'mysql': ensure => present,} does not.

Exactly!  I want to build classes to be used as building blocks.  I don't
want to have to deal with unexpected package collisions between two
classes because the authors of the two classes didn't know the package
was being used by the other.  That's ultimately where this discussion came
from.  If a package needs a whole class wrapped around it, it should get one,
but if it "just needs to be present", then it shouldn't be required, IMHO.

 
node 'some.node.my.domain.com inherits basenode {
   include mysql
   include general_devel
   realize Package['mysql-client']
}

node basenode {
   include sudo
   include vpackage

   # realize all packages with this tag
   Package<| tag = 'utils' |>
}

class vpackage {

   # packages with tag => util get realized on all systems
   @package { 'curl':    tag => 'utils',}
   @package { 'htop':    tag => 'utils',}
   @package { 'lynx':    tag => 'utils',}
   @package { 'screen':  tag => 'utils',}
   @package { 'strace':  tag => 'utils',}
   @package { 'tcpdump': tag => 'utils',}
   @package { 'wget':    tag => 'utils',}
   @package { 'whois':   tag => 'utils', name =>
$vpackages::params::whois, }

   @package { 'mysql-client': name => $vpackages::params::mysqlclient, }
}

Exactly!  I want to build classes to be used as building blocks.  I don't
want to have to deal with unexpected package collisions between two
classes because the authors of the two classes didn't know the package
was being used by the other.  That's ultimately where this discussion came
from.  If a package needs a whole class wrapped around it, it should get one,
but if it "just needs to be present", then it shouldn't be required, IMHO.

One question though…I don't really understand what the $vpackages::params
stuff does.  Is there some puppet magic going on there?


thanks,
Michael
 

lamour

unread,
Aug 24, 2012, 4:44:44 PM8/24/12
to puppet...@googlegroups.com, ramin...@badapple.net
sigh.  my page timed out while I was editing this, and I ended up having to cut and paste
the whole thing back together, and I (obviously) pasted the wrong paragraph here.  This
is the correct one:

This example is awesome!  I tried out something similar in my test
environment, and it works great.  My major issue with doing it this way
is that it means that I can't see from the class which packages it's
requiring, but it's still pretty nice that I only have to maintain one list
of packages.  Also, it opens up a single point of failure for "all" classes,
if someone screws up this file.  We may eventually go to something like
this and just wrap the editing of this file in a perl script with lots of error
checking.  lol


sorry for the confusion,
Michael
Reply all
Reply to author
Forward
0 new messages