Re: [Puppet Users] Re: Negate or uninclude a class
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
[Puppet Users] Re: Negate or uninclude a class
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-us...@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscr...@googlegroups.com. For more options, visit this group at
Re: [Puppet Users] Re: Negate or uninclude a class
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
[Puppet Users] Re: Negate or uninclude a class
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
Re: [Puppet Users] Re: Negate or uninclude a class
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-us...@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.
[Puppet Users] Re: Negate or uninclude a class
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-us...@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.
Re: [Puppet Users] Re: Negate or uninclude a class
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-us...@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.