On Thursday, July 5, 2012 5:34:13 AM UTC-5, fpee wrote: > > Hello puppet masters, I am cleaning up some puppet modules, using > puppet-lint. The warning I am getting is: > > top-scope variable being used without an explicit namespace > > I can turn this particular check off, but in doing my research I'm > finding all sorts of messages saying to avoid using +=
Good advice. > , to avoid using > variables in the node scope, Good advice, but sometimes difficult to apply. > and to switch to a parameterized class > whenever possible. Bad, *bad* advice. PuppetLabs did a pretty good job of promoting parametrized classes when it first introduced them, but the design was deeply flawed. The idea clashes with Puppet's model of classes as singletons, and the worst of the flaws spring from that mismatch. Only if you're using an ENC should you even consider class parametrization (a manifest set designed with an ENC in mind can in principle overcome the worst problems attending class parametrization), but think twice even then. Puppet 3 does better by tying class parameters to hiera, allowing class parameters to serve as a structured shortcut to external data, and providing a means to wean all the poor folks that invested development time in parametrized classes. Even if you're aiming for Puppet 3, however, your effort would be better spent on externalizing data for access via hiera than on parametrizing your classes. > Okay, I'm game. > > So, to understand what I'm doing, I'm setting up a yum repository and > limiting the includepkgs line to the very minimum amount of packages for > reasons of security / policy / insanity / etc. > > Here is the current implementation of this (which works fine). > > node standard { > $epel_includepkgs += 'puppet augeas-libs facter ruby-augeas ruby-shadow > ' > class { 'repo_epel': stage => 'pre' } > #other stuff > } > The worst thing about run stages in Puppet 2 is that you can only use them via the parametrized class syntax, which brings the worst problems of parametrized classes even to non-parametrized classes. Of course, run stages are purely syntactic sugar anyway. > node 'my.node1' inherits standard { > include denyhosts > } > > node 'my.node2' inherits standard { > include denyhosts > include gitlabhq > } > > class repo_epel { > yumrepo { 'epel': > enabled => 1, > descr => 'Extra Packages for Enterprise Linux 6 - > \$basearch', > mirrorlist => > 'https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=\$basearch', > failovermethod => priority, > gpgcheck => 1, > gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6', > require => File['/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6'], > includepkgs => $epel_includepkgs, > } > # other stuff > } > > class denyhosts { > $epel_includepkgs += 'denyhosts ' > # other stuff > } > > class gitlabhq { > $epel_includepkgs += 'libyaml gitolite git-all rvm ' > # other stuff > } > > my.node1, and my.node2 will have different (and correct) includepkgs > doing it this way (I have like .. 30+ modules for epel and more of other > repos to give you an idea) > If that's so then you are relying on a Puppet bug, or perhaps you have oversimplified your example. The language guide specifically states that the += operator affects the observed value of the affected variable only in the scope where the plussignment is performed. You definitely should not see the modified value in classes that are not declared in the scope of the plussignment. > To get rid of the error I tried making the variable $::epel_includepkgs, > but that generates the error: > err: Could not parse for environment production: Cannot assign to > variables in other #namespaces Right, because plussignment doesn't change the values of existing variables. It merely shadows those values with supplemented ones, and only within the scope where the plussignment appears. Dynamic scoping allows classes and resources to see that local value when their declarations appear in the same scope or a deeper-nested one, but that's a problem because classes can be included more than once, from different scopes. If those scopes provide different values for the same, needed variable then which one does such a class use? For all intents and purposes, it's unpredictable. > So what is the 'proper' puppet way to accomplish this? > Puppet DSL does not provide a mechanism for constructing values incrementally. Even what you're currently doing probably doesn't work quite the way you think it does. There are ways to approach it if you can assume strict nesting of all the scopes that are expected to contribute values, but that's not your case. One messy, but valid way to do this might be to manage the inclusion of packages in a repo's includepkgs via instances of a defined type that relies on an exec. Each instance of that type would ensure that or more included packages were listed for the specified repo, and they could all be declared independently, wherever the package itself is declared. Then don't manage the 'includepkgs' property of the Yumrepo resource so that you don't have clashes. Alternatively, you could probably write a couple of custom functions to manage a named, updatable data cubbyhole to use the way you are currently using plussignment. That would silence the warnings, but you would still have to deal with the issue of ensuring that all the needed values had been appended before the result was read out. I think you could work out something in that regard via class inheritance. Or you could switch to Ruby DSL, at least in strategic places. That would give you more freedom, but you would still need to handle the problem of accumulating all the needed values before reading them out. John -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To view this discussion on the web visit https://groups.google.com/d/msg/puppet-users/-/J2DtcXbtDFMJ. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.