Hi guys, Is there any functionality to negate or uninclude a class so as to stop it''s resources being declared? I''m thinking along the lines of having some classes included by default, but in very select circumstances to not include it. For example, LDAP auth on all servers except the actual LDAP servers themselves. Is the only way to do this to inherit the base class and override all it''s resources to do the equivalent of "ensure => absent", then something like "if (tagged(class)) { include undo-subclass } " where needed? Thanks, -Luke -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On Mon, Oct 18, 2010 at 02:19:38AM -0700, luke.bigum wrote:> Hi guys, > > Is there any functionality to negate or uninclude a class so as to > stop it''s resources being declared? I''m thinking along the lines of > having some classes included by default, but in very select > circumstances to not include it. For example, LDAP auth on all servers > except the actual LDAP servers themselves.No, you can''t uninclude a class.> > Is the only way to do this to inherit the base class and override all > it''s resources to do the equivalent of "ensure => absent", then > something like "if (tagged(class)) { include undo-subclass } " where > needed?You''ll have to do it the other way round and optionally include. In the base server class, have a little block like if $ldap_auth { include ldap::auth } Then just make sure that this variable is set true by default and set it explicitly to false for your ldap servers, either in their nodes or (more logically) in the ldap server class. You *could* do it with overrides but only If you were using a define within your base class for part of the setup and that define took a parameter which told it whether to include the ldap class. Trivial example: ----------------------------------------------------------------- define includer ( $include = true ) { if $include { include ldap } } class base { includer { ''setup'': } } class child inherits base { Includer[''setup''] { include => false } } ----------------------------------------------------------------- I wouldn''t do it that way unless there were other specific benefits to the define, though. The variable method is simpler. -- Bruce What would Edward Woodward do? -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On Oct 18, 4:38 am, Bruce Richardson <itsbr...@workshy.org> wrote:> No, you can''t uninclude a class.Right.> > Is the only way to do this to inherit the base class and override all > > it''s resources to do the equivalent of "ensure => absent", then > > something like "if (tagged(class)) { include undo-subclass } " where > > needed?[...]> You *could* do it with overrides but only If you were using a define > within your base class for part of the setup and that define took a > parameter which told it whether to include the ldap class.You could write it that way, but Puppet''s subclassing feature is designed precisely so that you don''t need to do so. It goes something like this: class ldap::client { # whatever resources are needed, such as ... file { "some-config-file": source => "normal-source" } } class ldap::client::disabled inherits ldap::client { # Override parent class resources as appropriate, # for example ... File["some-config-file"] { source => "alternative-source" } } node default { include "ldap::client" } node "my-ldap-server" inherits default { include "ldap::client::disabled" } It does not matter that node "my-ldap-server" inherits node "default", so that "my-ldap-server" directly or indirectly includes both "ldap::client" and "ldap::client::disabled". If a subclass overrides a property of a superclass''s resource, then it''s as if that property were changed *in the parent class* for nodes that include the subclass, and there is no conflict if a node includes both classes. That is perfectly suited to the situation here, and it also serves well in the event that class "ldap::client" may be included not just by nodes but also by other classes. Where you do not leverage those properties, you should not use subclasses. In a case such as the one we''re discussing here, however, subclasses can be a big win. For example, although Bruce''s main suggestion could be used if for some reason it were important to avoid subclasses, really in that case something akin to his define-based suggestion (but without subclasses) would be better. That way, if the LDAP client somehow gets turned on on your LDAP server, then Puppet will turn it back off. Unconfigured means "I don''t care"; it must not be confused with "off". The subclass usage pattern above achieves the same thing with no conditional inclusions and no define, plus it''s safe against inclusion of "ldap::client" by other parts of the manifest. Best, John -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On Mon, Oct 18, 2010 at 07:20:10AM -0700, jcbollinger wrote:> > On Oct 18, 4:38 am, Bruce Richardson <itsbr...@workshy.org> wrote: > > No, you can''t uninclude a class. > > Right. > > > > Is the only way to do this to inherit the base class and override all > > > it''s resources to do the equivalent of "ensure => absent", then > > > something like "if (tagged(class)) { include undo-subclass } " where > > > needed? > > [...] > > > You *could* do it with overrides but only If you were using a define > > within your base class for part of the setup and that define took a > > parameter which told it whether to include the ldap class. > > You could write it that way, but Puppet''s subclassing feature is > designed precisely so that you don''t need to do so.Um, I completely disagree with you and the rest of your post actually backs this up. Class inheritence *only* makes sense if you want to override the properties of resources. The OP wants not to include a whole class; what you''re telling him to do is not uninclude the class, but to try and override properties in every resource owned by the class, so as to make the class effectively do nothing. There are any number of reasons why that''s not a smart thing to do, but here are several that occur to me immediately. 1. If the resources in the ldap::client class change, the ldap::client::disabled will have to be changed to match. This just begs to be a source of error. 2. The structure of the ldap::client class and it''s resources may well have to be distorted to fit this arrangement. Some resources would have to be set up quite carefully so that they could be "negated". 3. What do you do about virtual resources that are realized in the parent class? You can''t unrealize them and if you override their properties, you may well conflict with other modules or classes which use them. # 4. What do you do about any other classes that are included in the parent class? Are you going to include "::disabled" versions of those in the ldap::client::disabled class? What if those classes are included elsewhere? Your exmaple cannot achieve the same effect as not including a class; the empty files you''d litter the filesystem with is only one example. Forcibly negating everything in a class is not the same as not including it. Why not just not include it?> For example, although Bruce''s main suggestion could be used if for > some reason it were important to avoid subclasses, really in that case > something akin to his define-based suggestion (but without subclasses) > would be better. That way, if the LDAP client somehow gets turned on > on your LDAP server, then Puppet will turn it back off. Unconfigured > means "I don''t care"; it must not be confused with "off". The > subclass usage pattern above achieves the same thing with no > conditional inclusions and no define, plus it''s safe against inclusion > of "ldap::client" by other parts of the manifest.I''m sorry, but I think you are quite wrong and your recommendations are very unwise. I have no objection to class inheritance at all, although the way it works in puppet is often misunderstoon and it is often overused as a result. Your proposed example is definitely not a good use of class inheritance. "ssh::server::disabled" makes sense, because that''s done by overriding the properties of an existing service resource to make sure it''s disabled. ldap::client::disabled does not make sense; the OP wants the actions in ldap::client not to be applied, not to be differently applied. By far the simplest and safest way not to include a whole class is the "if $ldap_enabled { include ldap::client }" method; it has no bad side effects, it works no matter how the internals of the ldap::client change, it''s a tiny bit of code. -- Bruce I see a mouse. Where? There, on the stair. And its clumsy wooden footwear makes it easy to trap and kill. -- Harry Hill -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On 10/18/2010 05:24 PM, Bruce Richardson wrote:> On Mon, Oct 18, 2010 at 07:20:10AM -0700, jcbollinger wrote: >> >> On Oct 18, 4:38 am, Bruce Richardson <itsbr...@workshy.org> wrote: >>> No, you can''t uninclude a class. >> >> Right. >> >>>> Is the only way to do this to inherit the base class and override all >>>> it''s resources to do the equivalent of "ensure => absent", then >>>> something like "if (tagged(class)) { include undo-subclass } " where >>>> needed? >> >> [...] >> >>> You *could* do it with overrides but only If you were using a define >>> within your base class for part of the setup and that define took a >>> parameter which told it whether to include the ldap class. >> >> You could write it that way, but Puppet''s subclassing feature is >> designed precisely so that you don''t need to do so. > > Um, I completely disagree with you and the rest of your post actually > backs this up. Class inheritence *only* makes sense if you want to > override the properties of resources. The OP wants not to include a > whole class; what you''re telling him to do is not uninclude the class, > but to try and override properties in every resource owned by the class, > so as to make the class effectively do nothing. There are any number of > reasons why that''s not a smart thing to do, but here are several that > occur to me immediately. > > 1. If the resources in the ldap::client class change, the > ldap::client::disabled will have to be changed to match. This > just begs to be a source of error. > > 2. The structure of the ldap::client class and it''s resources may > well have to be distorted to fit this arrangement. Some resources > would have to be set up quite carefully so that they could be > "negated". > > 3. What do you do about virtual resources that are realized in the > parent class? You can''t unrealize them and if you override their > properties, you may well conflict with other modules or classes which > use them. # > > 4. What do you do about any other classes that are included in the > parent class? Are you going to include "::disabled" versions of > those in the ldap::client::disabled class? What if those classes > are included elsewhere? > > Your exmaple cannot achieve the same effect as not including a class; > the empty files you''d litter the filesystem with is only one example. > Forcibly negating everything in a class is not the same as not including > it. Why not just not include it? > >> For example, although Bruce''s main suggestion could be used if for >> some reason it were important to avoid subclasses, really in that case >> something akin to his define-based suggestion (but without subclasses) >> would be better. That way, if the LDAP client somehow gets turned on >> on your LDAP server, then Puppet will turn it back off. Unconfigured >> means "I don''t care"; it must not be confused with "off". The >> subclass usage pattern above achieves the same thing with no >> conditional inclusions and no define, plus it''s safe against inclusion >> of "ldap::client" by other parts of the manifest. > > I''m sorry, but I think you are quite wrong and your recommendations are > very unwise. I have no objection to class inheritance at all, although > the way it works in puppet is often misunderstoon and it is often > overused as a result. Your proposed example is definitely not a good > use of class inheritance. > > "ssh::server::disabled" makes sense, because that''s done by overriding > the properties of an existing service resource to make sure it''s > disabled. ldap::client::disabled does not make sense; the OP wants the > actions in ldap::client not to be applied, not to be differently > applied. > > By far the simplest and safest way not to include a whole class is the > "if $ldap_enabled { include ldap::client }" method; it has no bad side > effects, it works no matter how the internals of the ldap::client > change, it''s a tiny bit of code. >Hi Bruce, I was glad for John''s comment on your answer because it mirrored my sentiment exactly, and I in turn disagree with most of what you''ve written here. Subclasses that effectively disable a class are a sound concept. How this has to be achieved in any specific case can be somewhat mind-boggling, but the variable approach has severe limitations of its own. 1. Where is the variable set? You have probably no problem when using external node definition, but not everybody does. You cannot define the variable in an arbitrary part of your manifest, because you can be afflicted by both ordering and scoping issues. 2. The concept of dynamic scoping is going away in future versions (at least that is what seems to be a community consensus). Again, if you can globally assign the variable value to your node, this is not a problem. But if you want to for every node that includes class B to automatically not include class A, you''re out of luck (this is true in many cases today already, because of the scoping issues). Example that works: class default { include A } node X { include default include B } class B { include A::disable ... } Example which will probably not work: class default { if ! $a_disabled { include A } } node X { include default include B } class B { $a_disabled = true ... } This will not work because in the scope of class default, the variable has not been defined. Variables are about as far as you can get from a panacea in the puppet DSL. Granted, class inheritance can be clumsy, awkward and unmaintainable in many cases. But all that and more applies to variables as well, and it seems to me that variables are going to become a lot less useful for such purposes in the future. Class parameters will probably be an alternative that can be used for solutions that are superior to both the above, but I cannot yet say much about that. Sincerely, Felix -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On Oct 18, 10:24 am, Bruce Richardson <itsbr...@workshy.org> wrote:> Class inheritence *only* makes sense if you want to > override the properties of resources.It appears that we agree there. I add that one property shared by most resources is "ensure", by which relevant resources can be ensured absent / disabled (among other things).> The OP wants not to include a > whole class; what you''re telling him to do is not uninclude the class, > but to try and override properties in every resource owned by the class, > so as to make the class effectively do nothing.The OP asked about how to "uninclude" a whole class -- that is, given the class being included in one part of a manifest, how to elsewhere cause it to not be included after all. We agree that cannot be done. One alternative approach is to include the class conditionally in the first place, a different alternative is to override it where needed. *Neither* is what the OP actually asked for. The subclass approach definitely does not override the superclass to do nothing. Much to the contrary, it overrides the superclass so that together (whether the superclass is directly included or not) they ensure the correct configuration for a system that is not, in the example, an LDAP client. In other words, the servers are configured as non-clients, rather than leaving their client status unmanaged. There will be file differences between clients and non-clients, and possibly differences in such things as installed packages and service configuration. It is wise to manage those differences, whether whether via subclassing or otherwise.> There are any number of > reasons why that''s not a smart thing to do, but here are several that > occur to me immediately.[...] All the reasons cited boil down to this: the superclass and subclass must be structured suitably and be tightly coupled in order to work correctly. This is true generally of Puppet subclassing. It may constitute too great a barrier for some uses, but that does not invalidate the approach in general. How that relates to the OP''s problem depends on his manifests.> Your exmaple cannot achieve the same effect as not including a class; > the empty files you''d litter the filesystem with is only one example. > Forcibly negating everything in a class is not the same as not including > it. Why not just not include it?The subclass approach indeed does not have the same effect as not including a class in the first place, but that''s not exactly what the OP asked for. As described above, it also wouldn''t be the best practice, because it would leave client status unmanaged on the servers. Whatever problems the subclass appoach has, though, empty files is not one of them. Perhaps you''re looking at how in my simplified example I overrode the "source" property of a File resource. That contemplates a situation where you want the file present in any case, but with different content (e.g. /etc/nsswitch.conf). If you only want the file present at all in one case or the other then you would override the "ensure" property instead.> > For example, although Bruce''s main suggestion could be used if for > > some reason it were important to avoid subclasses, really in that case > > something akin to his define-based suggestion (but without subclasses) > > would be better. That way, if the LDAP client somehow gets turned on > > on your LDAP server, then Puppet will turn it back off. Unconfigured > > means "I don''t care"; it must not be confused with "off". The > > subclass usage pattern above achieves the same thing with no > > conditional inclusions and no define, plus it''s safe against inclusion > > of "ldap::client" by other parts of the manifest. > > I''m sorry, but I think you are quite wrong and your recommendations are > very unwise.Then we will have to agree to disagree on that point. It is altogether independent of the subclassing question, however, and I think it very important, so I repeat: "Unconfigured means ''I don''t care''; it must not be confused with ''off''." For example, if it is important that a system not be configured as an LDAP client, then its manifests should affirmatively make that so. It is not sufficient just to leave the client configuration out of its manifest. What if an admin (or a bad Puppet manifest) enables the LDAP client on a system that should not have it? Or what if one wants to convert a client to a server? You do not need to use subclasses to address the problem (the define-based approach could do it), but merely omitting the client configuration from the machine''s manifest doesn''t cut it.> I have no objection to class inheritance at all, although > the way it works in puppet is often misunderstoon and it is often > overused as a result.We agree on this. All too often, Puppeteers inherit from a class where it would be better to include that class.> Your proposed example is definitely not a good > use of class inheritance.My example was a schematic of the form, not a practical one of a particular solution. I vigorously maintain, however, that a direct consequence of the design of Puppet''s subclassing a feature is that when you use subclasses properly, you do not need or want to conditionally include superclass vs. subclass. If a superclass and subclass don''t work together correctly when both are included in the same manifest, then they are constructed poorly. It is primarily that usage model that my example was intended to illustrate, and if you disagree with the propriety of that model (leaving aside its application to the present problem) then I think you are missing some of the power and benefits of subclasses. [...]> By far the simplest and safest way not to include a whole class is the > "if $ldap_enabled { include ldap::client }" method; it has no bad side > effects, it works no matter how the internals of the ldap::client > change, it''s a tiny bit of code.If avoiding inclusion of a certain class under certain circumstances is indeed what you want to do, then all the methods Puppet provides to do so are pretty much equivalent to that. Doing so would be independent of the details of the class in question, and it would not require much code. All that is agreed. That approach must be applied everywhere that class in question may be included, however. Depending on the manifests, that could present a maintenance problem (but probably not in the OP''s case). Moreover, it would leave the client status unconfigured for some systems. That might be acceptable if Puppet is used primarily for provisioning, but it prevents Puppet from *maintaining* the (non-)client state. An approach involving subclassing is not necessarilly viable or appropriate, but if done right it involves solves the problem of maintaining state after provisioning, it does not require attention to where the superclass may be included, and it is simple to express in a node configuration. It does require more code overall, but that''s because it *does* more. The additional code is all encapsulated in the classes'' module. It is not useful to conditionally include super- vs. subclass in this case; one or both classes are broken if they don''t have the correct result when both are included in the same manifest. A non-subclass approach that also maintains non-client state after provisioning would require roughly as much code as the subclass approach would, because it must address the same configuration details. Such an approach would rely on conditional inclusion of one class vs. another, with the associated benefits and drawbacks. The only reason I see to prefer this alternative would be if the structure of the proposed superclass is too complicated for subclassing to be viable, but I''m having trouble seeing how that would not also present a problem for writing an independent non-client class. Regards, John -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On Tue, Oct 19, 2010 at 01:36:25PM +0200, Felix Frank wrote:> > Subclasses that effectively disable a class are a sound concept.Subclasses which disable a resource are a sound concept; subclasses which attempt to negate a claass present many problems, some of which I have described, none of which you hae addressed.> How > this has to be achieved in any specific case can be somewhat > mind-boggling,Yes, indeed. All the problems of virtual resources, other included classes, requirement to extend the disabling class every time the basic class is changed and so on. And you''ve presented no solutions to any of those.> but the variable approach has severe limitations of its own. > > 1. Where is the variable set? You have probably no problem when using > external node definition, but not everybody does.You can do it in an internal node definition too. Is there a law against node definitions in your manifests? But let''s assume somebody doesnt'' want to or cannot use nodes. That isn''t a problem; I''ve designed Puppet configurations that used no nodes at all, or a default node which simply included a class based on the node''s hostname. Still works - just declare the variable at the right level.> You cannot define the > variable in an arbitrary part of your manifest, because you can be > afflicted by both ordering and scoping issues.I wouldn''t try to declare it in an arbitrary location. I would declare it in an appropriate location.> > 2. The concept of dynamic scoping is going away in future versions (at > least that is what seems to be a community consensus). Again, if you can > globally assign the variable value to your node, this is not a problem.It''s not that I''m in love with the way Puppet uses variables - I certainly amd not - my objection is to the concept of trying to negate a class by individually trying to break or undo all it''s effects. That latter option is a horrible mess. Unless the community also proposes to do away with "if", "case" and selectors, there is always going to be a way of saying "if <condition> { include ldap::client }" and that is always going to be a better solution for the problem *as described by the original poster*, which is what I was answering.> But if you want to for every node that includes class B to automatically > not include class A, you''re out of luck (this is true in many cases > today already, because of the scoping issues).Well, you''ve finally given an example that raises a genuine problem, but the first thing to say is that it''s not the problem described by the poster. Secondly, the problem you describe can be solved by some variant of if $variable { include A } else { include B } Even if we outlaw simple variables, there are other ways to to signal state; parameterized classes, defines, creative abuse of virtual defines, all of them are better than the idea of negating a class resource by resource.> > Variables are about as far as you can get from a panacea in the puppet > DSL. Granted, class inheritance can be clumsy, awkward and > unmaintainable in many cases.Class inheritance is very elegant when used for what it is good for. It is bad for the purposes of the original poster.> But all that and more applies to variables > as well, and it seems to me that variables are going to become a lot > less useful for such purposes in the future.Wonderful. As I said, I''m not in love with Puppet''s variables. I''ve worked with declaritive languages before - done major projects in XSLT and XSLT - and I''ll be delighted to see more structured, less messy ways of working. I''d be even more delighted to see some of what are currently functions become genuine keywords. But if you''re telling me that the community is not just proposing to remove dynamic variable scope but also to remove the ability to say "if <condition> { include class }", not provide any alternatives and force people to have to clumsily override every resource in a class which they never wanted to include in the first place, then I''m afraid that the community is an ass. Hopefully, that''s not what you''re telling me. -- Bruce It is impolite to tell a man who is carrying you on his shoulders that his head smells. -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On Tue, Oct 19, 2010 at 09:00:16AM -0700, jcbollinger wrote:> The subclass approach definitely does not override the superclass to > do nothing. Much to the contrary, it overrides the superclass so that > together (whether the superclass is directly included or not) they > ensure the correct configuration for a system that is not, in the > example, an LDAP client. In other words, the servers are configured > as non-clients, rather than leaving their client status unmanaged. > There will be file differences between clients and non-clients, and > possibly differences in such things as installed packages and service > configuration. It is wise to manage those differences, whether > whether via subclassing or otherwise.That''s topsy turvy, in my opinion. I agree with you about the importance of state, but in that scenario, to me, not being an LDAP client is the basic state. The basic, clean state of a system should be something Puppet protects from the start; including classes should modify or extend that and, in most cases, I expect my configuration to be protective enough of the core and well known functionality so that it should make no difference whether a class was previously included and then dropped or never included in the first place. Here''s my rationale: most of us do not have the luxury of knowing everything about every aspect of every package that may be installed on a typical Linux/*nix system (unless you''re the chief architect at Red Hat/SuSE or wherever, in which case you may have a shot). That isn''t a terrible problem; we can know enough about the core to be aware of what is significant. I certainly know enough about the core components of a system (nsswitch, pam, fstab and so on), to know what will interfere with that and what is irrelevant. The seed of any configuration, for me, would be locking those down in their simple and functional state. This means that including an ldap::client will extend that, but in the absence of ldap::client, the core function will be restored. There are cases where the past inclusion of a class will litter a system with packages and configuration that do interfere, but those are rare. I do not share your nervousness about purging - purge and well managed resources - and judicious use of virtual ones - is generally cleaner than a whole set of twinned active/inactive classes. It doesn''t mean I never, ever write a disable/cleanup class but it isn''t my habit. It''s a defensive approach but, given that I''m not Red Hat''s chief architect, lack the time to weigh every package in the balance but do have responsibility for relatively up to date Red Hat and Centos systems (Debian too, but that''s a slower moving target), it seems to me both saner and less work than adding disable classes to everything. It''s also less work and the code is cleaner, so I''d probably do it even if I were the very source of all knowledge of RHEL''s eccentricities. My basic samba class configures a minimal smb.conf to be aware of the local workgroup/domain but have no shares and explicitly disables all samba-related services. samba::member, samba::pdc and others inherit and extend. No longer including them undoes the damage, so to speak. This is more than semantic quibbling about how to label different states; inheriting and overriding a more complex state to impose a simpler state is not the same as defaulting to the simpler state. So in my situation, "if <condition> { include class }" works very well. -- Bruce Explota!: miles de lemmings no pueden estar equivocados. -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On Oct 19, 6:04 pm, Bruce Richardson <itsbr...@workshy.org> wrote:> [...] I agree with you about the > importance of state, but in that scenario, to me, not being an LDAP > client is the basic state.After much consideration, I think a great deal of this debate hinges on that definition. It is perfectly reasonable, but not exclusively so. For instance, my basic state is for systems to be NIS clients. It seems most reasonable to me for the basic state to provide those configuration details from which few of my systems deviate. The OP''s, at present, is for systems to be LDAP clients.> The basic, clean state of a system should be > something Puppet protects from the start; including classes should > modify or extend that and, in most cases, I expect my configuration to > be protective enough of the core and well known functionality so that > it should make no difference whether a class was previously included and > then dropped or never included in the first place.I don''t quite understand that. How does your configuration protect the basic state of a system without including classes? You could use global resources, but then those could not be overridden. I suspect that instead you have one or more core classes that you include on every node to establish and maintain the basic state; that seems consistent with your further comments. Particular nodes then include *other* classes to modify or extend. [...]> I certainly know enough about the core components of a > system (nsswitch, pam, fstab and so on), to know what will interfere > with that and what is irrelevant. The seed of any configuration, for > me, would be locking those down in their simple and functional state. > This means that including an ldap::client will extend that, but in the > absence of ldap::client, the core function will be restored.I think you''re saying that you would implement ldap::client itself using subclassing if (and only if) it needs to alter anything in the core. There''s merit to that, and doing it that way could indeed have exactly the results you describe. No further subclass would be required. But how does this apply to the OP? His current basic state is for systems to be LDAP clients. That''s not what you would choose, but if he retains that choice, then does not your approach call for subclassing where a node must not be an LDAP client? Such nodes would then include ldap::client::disabled to override the base, and dropping that class would restore base functionality, just as you recommend. In all likelihood, such a subclass could be very slim: it probably needs to override only a small number of resources to disable the client (maybe just /etc/nsswitch.conf); it shouldn''t need to completely counter everything in ldap::client.> I do > not share your nervousness about purging - purge and well managed > resources - and judicious use of virtual ones - is generally cleaner > than a whole set of twinned active/inactive classes. It doesn''t mean I > never, ever write a disable/cleanup class but it isn''t my habit.I''m curious: what types of resources do you purge, in what contexts? Your configuration philosophy seems similar to mine in that you don''t try to manage every system detail, but that rather limits the available scope for purging, doesn''t it? [...]> This is more than semantic quibbling about how to label different > states; inheriting and overriding a more complex state to impose a > simpler state is not the same as defaulting to the simpler state.Much then depends on the chosen measure of complexity. I think you mean to judge by some measure of distance between the target state and a base reference state, which I take to be your "basic" / "clean" state. Your recommendations then make good sense when you stipulate the existance of a default state to fall back on, especially when coupled with purging to clean up potentially troublesome unwanted resources (thanks for those clarifications). How that applies to the OP''s case is a different question, however. If he continues to rely on a base state in which the LDAP client is enabled, then overriding that state to disable the client leads to a more complex state (by the above standard). As I said at the beginning, much seems to hinge on the choice of base state. Our positions now seem much closer than they originally did. I won''t argue over how a system''s base state should be constituted -- that''s too subjective -- and otherwise we seem largely to agree. Overall, my main objection to your original response was about your claim that a subclass-based solution would require use of defines and conditionals. You seem to have backed off on that, so I think we''re good. Cheers, John -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
On 10/19/2010 07:07 PM, Bruce Richardson wrote:> On Tue, Oct 19, 2010 at 01:36:25PM +0200, Felix Frank wrote: >> >> Subclasses that effectively disable a class are a sound concept. > > Subclasses which disable a resource are a sound concept; subclasses > which attempt to negate a claass present many problems, some of which I > have described, none of which you hae addressed.Well, that''s true.> 1. If the resources in the ldap::client class change, the > ldap::client::disabled will have to be changed to match. This > just begs to be a source of error.Yes. :-) Potential maintenance nightmare that cannot easily be avoided.> 2. The structure of the ldap::client class and it''s resources may > well have to be distorted to fit this arrangement. Some resources > would have to be set up quite carefully so that they could be > "negated".If you have resources like "mount" in mind, I''m again inclined to concur. On the other hand, "mount" is a good example for a resource where "no longer including the class" won''t do you any good wrt. lingering resources on the client. But you have gone into this to some detail in the other branch with John, so I''d consider this point addressed.> 3. What do you do about virtual resources that are realized in the > parent class? You can''t unrealize them and if you override their > properties, you may well conflict with other modules or classes which > use them. #Interesting point, I don''t think I''ve yet used virtual resources to the extent you imply. It presents a problem that would have to be addressed using more syntactical convolution, not dissimilar from point (2).> 4. What do you do about any other classes that are included in the > parent class? Are you going to include "::disabled" versions of > those in the ldap::client::disabled class? What if those classes > are included elsewhere?If disabling the base class necessarily implies disabling the included class, this is the correct thing to do. In most cases though, where ldap::client includes things it needs, but which otherwise are not unique to ldap clients, forbidding their presence in this way is a semantical error and should be avoided. Deciding this is (as always) up to the designer. And yes, it is another layer of complication for this approach.>> but the variable approach has severe limitations of its own. >> >> 1. Where is the variable set? You have probably no problem when using >> external node definition, but not everybody does. > > You can do it in an internal node definition too. Is there a law > against node definitions in your manifests? But let''s assume somebody > doesnt'' want to or cannot use nodes. That isn''t a problem; I''ve > designed Puppet configurations that used no nodes at all, or a default > node which simply included a class based on the node''s hostname. Still > works - just declare the variable at the right level.Exactly. In a variable driven environment, where there are places (nodes, external definitions, a central class with a node''s manifest root) that fit the definition of "the right level", this is the most sane approach. Using other design paradigms, however, there may not be a "right level" to do that. There is a reason for variable scoping biting many.>> You cannot define the >> variable in an arbitrary part of your manifest, because you can be >> afflicted by both ordering and scoping issues. > > I wouldn''t try to declare it in an arbitrary location. I would declare > it in an appropriate location.Consider this manifest structure (that I in *no way* endorse): node base_node { include default_stuff } node ldap_server1 inherits base_node { ... } class default_stuff { include ldap::client } The inclusion of ldap::client is in the scope of base_node, and thus likely outside the area where normal nodes are allowed to change its environment. You could conceive horrors like class default_stuff { $exclude_ldap_client = "" if $exclude_ldap_client != "true" { include ldap::client } } class ldap::server { $default_stuff::exclude_ldap_client += "true" } Which is arguably distasteful.>> >> 2. The concept of dynamic scoping is going away in future versions (at >> least that is what seems to be a community consensus). Again, if you can >> globally assign the variable value to your node, this is not a problem. > > It''s not that I''m in love with the way Puppet uses variables - I > certainly amd not - my objection is to the concept of trying to negate a > class by individually trying to break or undo all it''s effects. That > latter option is a horrible mess. Unless the community also proposes to > do away with "if", "case" and selectors, there is always going to be a > way of saying "if <condition> { include ldap::client }" and that is > always going to be a better solution for the problem *as described by > the original poster*, which is what I was answering.I guess our notions of the original problem differ somewhat. Seeing as I admit to many of your concerns being quite true, your approach may be more fitting in the general case, that being: a) the manifest has central locations (like elaborate node definitions) where setting "node global" variables is not a problem and b) the class that needs unincluding is rather complex If both aren''t given (maybe an edge case), I''d still lean towards the subclassing approach.>> But if you want to for every node that includes class B to automatically >> not include class A, you''re out of luck (this is true in many cases >> today already, because of the scoping issues). > > Well, you''ve finally given an example that raises a genuine problem, but > the first thing to say is that it''s not the problem described by the > poster.It is. Whoever includes ldap::server is not to include ldap::client. (Well yes, I sort of invented that first part, but this is what I''d consider a clean structure in puppet terms.)> Secondly, the problem you describe can be solved by some > variant of > if $variable { > include A > } else { > include B > }You''re kidding, right? Putting this in pseudo-logical terms, what I asked for was B => !A and you''re proposing !A => B and !B => A So everytime I want something to not be an ldap client, it must become an ldap server?> Even if we outlaw simple variables, there are other ways to to signal > state; parameterized classes, defines, creative abuse of virtual > defines, all of them are better than the idea of negating a class > resource by resource.Very good point. My arsenal is very limited wrt. to the approaches mentioned above. For most given problems, I can imagine that one (or a combination) of those listed above fits much better than the plain subclassing approach by itself.>> Variables are about as far as you can get from a panacea in the puppet >> DSL. Granted, class inheritance can be clumsy, awkward and >> unmaintainable in many cases. > > Class inheritance is very elegant when used for what it is good for. It > is bad for the purposes of the original poster....based on your assumptions about the OP''s manifest.>> But all that and more applies to variables >> as well, and it seems to me that variables are going to become a lot >> less useful for such purposes in the future. > > Wonderful. As I said, I''m not in love with Puppet''s variables. I''ve > worked with declaritive languages before - done major projects in XSLT > and XSLT - and I''ll be delighted to see more structured, less messy ways > of working. I''d be even more delighted to see some of what are > currently functions become genuine keywords. But if you''re telling me > that the community is not just proposing to remove dynamic variable > scope but also to remove the ability to say "if <condition> { include > class }", not provide any alternatives and force people to have to > clumsily override every resource in a class which they never wanted to > include in the first place, then I''m afraid that the community is an > ass. Hopefully, that''s not what you''re telling me.I don''t believe it is :-) The idea is that class parameters, once they work flawlessly, can obsolete dynamic variable scoping. The latter can and should be done away with because of conceptional problems. The other language features you''re referring to are not subject to this development. In your initial response, you proposed wrapping the included class in a define, but warned against it. I''m not sure how a "2.7" approach should go about the problem, but I can imagine it might go kind of like class ldap(client=true) { if $client { include ldap::client } } class defaults { class { "ldap": } } class defaults_no_ldap_client inherits defaults { Class["ldap"] { client => false } } class ldap::server { include defaults_no_ldap_client } No littering your manifest with variables that float around wildly, and no wild overriding of multiple resources. Of course, this radically disagrees with John''s notion (and is actually a cleaner implementation of Bruce''s proposal). But after all, my point wasn''t what John was thinking of, and my primary problem is with flinging variables across class boundaries. Cheers, Felix -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.