It seems like a very common expectation that the following code would work: class boo { $me = "/something" file { $me: ensure => present } } class yay inherits boo { $me = "/something/else" } Yet, as many have found to their chagrin, it does not work. Should it? I believe I know how I could make this work: Create a single variable namespace for class hierarchies, such that a parent class and all of its subclasses would all set all of their variables in the same table, and that table would keep track of who set a given value and would follow the same rules that attributes follow right now (i.e., only subclasses can override a value). This would require two significant changes to the parser: First, we would no longer be creating a new scope for subclasses. This isn''t a huge change, but it''s not small either. Second, all variable dereferencing would have to become late-binding; that is, all variables in a given class hierarchy would need to be set before any of them are dereferenced. This is a significant amount of work, in no small part because it means that all ''include'' calls would need to be evaluated, along with all variables, then the rest of the system would get evaluated. At the least, this would require turning ''include'' back into a keyword, rather than a normal function, because you couldn''t evaluate, say, ''template'' calls until all classes and all variables had been evaluated. This would effectively turn Puppet into a two-pass parser -- the first pass would evaluate all ''include'' calls and all variable settings, and the second pass would evaluate everything else. Comments? Anyone like this feature so much they want to pay for it? :) -- SELF-EVIDENT, adj. Evident to one''s self and to nobody else. -- Ambrose Bierce --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
Luke Kanies <luke@madstop.com> writes:> It seems like a very common expectation that the following code would > work:> class boo { > $me = "/something" > file { $me: ensure => present } > }> class yay inherits boo { > $me = "/something/else" > }> Yet, as many have found to their chagrin, it does not work. Should it?I''m not sure that it should. We''re one of the big proponents of overrides, and they are really necessary for what we do, but they''re also a double-edged sword. They promote a lot of action at a distance, where you can''t figure out from the code by itself what''s going to happen and instead have to keep in mind the whole override tree. We already have this to some degree with overriding type parameters, but variables feel like a step farther. When I read code like: $me = "/something" file { $me: ensure => present } I would never expect $me to be something other than "/something". It''s very unintuitive, particularly for people who are used to imperative languages (which I know Puppet isn''t, but it''s still a hard mindset to shake). There''s a way of writing this code right now: class boo { file { "/something": ensure => present } } class yay inherits boo { File["/something"] { ensure => directory } file { "/something/else": ensure => present } } and while it may not be obvious that this is any better, it at least gets away from this business of having variables change their settings from what appears to be set in code directly above their use. I find it easier to think of type parameters as parameters of an object that can then be changed by another object that inherits from it. -- Russ Allbery (rra@stanford.edu) <http://www.eyrie.org/~eagle/>
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Wednesday 02 May 2007, Luke Kanies wrote:> It seems like a very common expectation that the following code would > work: > > class boo { > $me = "/something" > file { $me: ensure => present } > } > > class yay inherits boo { > $me = "/something/else" > } > > Yet, as many have found to their chagrin, it does not work. Should it?I find Russ'' argument very convincing. If I need something like this, I usually put the variable as "configuration" beside the actual class include. Many examples of this can be found in my site.pp at http://club.black.co.at:82/svn/manifests/trunk/manifests/site.pp This makes it obvious that the var is coming from outside and can have different values for different nodes. Regards, David - -- - - hallo... wie gehts heute? - - *hust* gut *rotz* *keuch* - - gott sei dank kommunizieren wir über ein septisches medium ;) -- Matthias Leeb, Uni f. angewandte Kunst, 2005-02-15 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFGOD6W/Pp1N6Uzh0URApbSAKCTS0MHIS9idl8grFvRFkcwtlJVDACeKYV9 fA21Y/TOeY2mtrop9oZ2rWs=qUTJ -----END PGP SIGNATURE-----
On May 2, 2007, at 2:32 AM, David Schmitt wrote:> I find Russ'' argument very convincing. If I need something like > this, I > usually put the variable as "configuration" beside the actual class > include. > Many examples of this can be found in my site.pp at > http://club.black.co.at:82/svn/manifests/trunk/manifests/site.pp > > This makes it obvious that the var is coming from outside and can have > different values for different nodes.Well, that makes it simpler, anyway. I''ll plan on sticking with the current system, then. -- No one who cannot rejoice in the discovery of his own mistakes deserves to be called a scholar. --Donald Foster --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Wednesday 02 May 2007, Luke Kanies wrote:> On May 2, 2007, at 2:32 AM, David Schmitt wrote: > > I find Russ'' argument very convincing. If I need something like > > this, I > > usually put the variable as "configuration" beside the actual class > > include. > > Many examples of this can be found in my site.pp at > > http://club.black.co.at:82/svn/manifests/trunk/manifests/site.pp > > > > This makes it obvious that the var is coming from outside and can have > > different values for different nodes. > > Well, that makes it simpler, anyway. I''ll plan on sticking with the > current system, then.This[1] should somehow find its way into ExternalNodeClassification. This seems to fit in as kind of server side facts. Or a kind of top level configuration. Regards, David [1] i.e. vars from node scope to steer included classes - -- - - hallo... wie gehts heute? - - *hust* gut *rotz* *keuch* - - gott sei dank kommunizieren wir über ein septisches medium ;) -- Matthias Leeb, Uni f. angewandte Kunst, 2005-02-15 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFGOPKA/Pp1N6Uzh0URAkQtAKCfsWqhNXBcd3pa3wD5TNXNM55ldACeNyF6 O0GOWERAduj7tYSqAEBt3EI=j+Wi -----END PGP SIGNATURE-----
On May 2, 2007, at 3:20 PM, David Schmitt wrote:> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On Wednesday 02 May 2007, Luke Kanies wrote: >> On May 2, 2007, at 2:32 AM, David Schmitt wrote: >>> I find Russ'' argument very convincing. If I need something like >>> this, I >>> usually put the variable as "configuration" beside the actual class >>> include. >>> Many examples of this can be found in my site.pp at >>> http://club.black.co.at:82/svn/manifests/trunk/manifests/site.pp >>> >>> This makes it obvious that the var is coming from outside and can >>> have >>> different values for different nodes. >> >> Well, that makes it simpler, anyway. I''ll plan on sticking with the >> current system, then. > > This[1] should somehow find its way into > ExternalNodeClassification. This > seems to fit in as kind of server side facts. Or a kind of top level > configuration.I see now that it''s not in there (I''ll rewrite; check the page again in, say, 20 mins), but my plan is for the node classing tool to produce two lists: The classes that the node should include, and a set of variables. Some of these variables would be directly from Facter, but some of them would be set in the tool based on whatever. This would make node variables equivalent to Facter variables in terms of their global nature. -- It has recently been discovered that research causes cancer in labratory rats. --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
Sorry to bump a slightly closed thread here, but I encountered the same problem with node inheritance last night and thought it worth commenting. Luke Kanies wrote:> It seems like a very common expectation that the following code would > work: > > class boo { > $me = "/something" > file { $me: ensure => present } > } > > class yay inherits boo { > $me = "/something/else" > } > > Yet, as many have found to their chagrin, it does not work. Should it? > > >I think it should, at least on node inheritance. I stumbled into this last night, when trying to do the following in my manifests: #---------------- $testname = "blah" node base_node { $testname = "base_node" include test_class include ssh::service } node dev_services_node inherits base_node { $testname = "dev_services_node" } node anise inherits dev_services_node { $testname = "anise" $sshd_config_type = "INTERNAL_DEV" } #---------------- I expected that the specification of the $sshd_config_type variable would result in it being set in the ssh::service class inherited from base_node. It doesn''t - ssh::service sees $ssh_config_type = '''', as it is undefined in base_node. As i understand from this thread and my testing, included classes are in the scope of the class or node that includes them, not in the scope of the class/node that inherits them. I can work around this I think using ''node type classes'' - i.e replace my dev_service_node node definition with a ''dev_services_class'' that includes all classes i''d require. Alternatively I guess I could rethink how I select my ssh server config file. It does make me wonder however how useful node inheritance is though - this is the only reason I see to use it, and at present it appears that I can only assign static classes to the top-level nodes which is not very practical. If anyone has any shining examples of how they do use node inheritance to their benefit, I''d love to see them. Thanks, mike -- Mike Pountney, Information Systems Manager, Semantico, Floor 1, 21-23 Dyke Road, Brighton BN1 3FE <http://www.semantico.com/> <mailto:Mike.Pountney@semantico.com> <tel:+44-1273-722222;ext=209> <fax:+44-1273-723232>
On Jun 5, 2007, at 4:32 AM, Mike Pountney wrote:> Sorry to bump a slightly closed thread here, but I encountered the > same > problem with node inheritance last night and thought it worth > commenting.Ok.> Luke Kanies wrote: >> It seems like a very common expectation that the following code would >> work: >> >> class boo { >> $me = "/something" >> file { $me: ensure => present } >> } >> >> class yay inherits boo { >> $me = "/something/else" >> } >> >> Yet, as many have found to their chagrin, it does not work. >> Should it? >> >> >> > I think it should, at least on node inheritance.I recently experimented with getting it to work, and it would require a completely different style of inheritance from class inheritance. I think the right solution is to implement kinial, and use it to perform this kind of override.> I stumbled into this last night, when trying to do the following in my > manifests: > > #---------------- > > $testname = "blah" > > node base_node { > $testname = "base_node" > include test_class > include ssh::service > } > > node dev_services_node inherits base_node { > $testname = "dev_services_node" > } > > node anise inherits dev_services_node { > $testname = "anise" > $sshd_config_type = "INTERNAL_DEV" > } > > #---------------- > > I expected that the specification of the $sshd_config_type variable > would result in it being set in the ssh::service class inherited from > base_node. It doesn''t - ssh::service sees $ssh_config_type = '''', as it > is undefined in base_node.Yeah, this is a very common expectation, but it doesn''t work because parent scopes are placed above child scopes, rather than below. This is exactly what you want for classes (in most but not all cases) yet you want the opposite for nodes. Thus, punt to kinial.> As i understand from this thread and my testing, included classes > are in > the scope of the class or node that includes them, not in the scope of > the class/node that inherits them. > > I can work around this I think using ''node type classes'' - i.e replace > my dev_service_node node definition with a ''dev_services_class'' that > includes all classes i''d require. Alternatively I guess I could > rethink > how I select my ssh server config file. > > It does make me wonder however how useful node inheritance is though - > this is the only reason I see to use it, and at present it appears > that > I can only assign static classes to the top-level nodes which is not > very practical.I agree; it''s not actually very useful. Thus, I''m enhancing it and making it a separate tool entirely (eventually). -- Don''t hit at all if it is honorably possible to avoid hitting; but never hit soft! -- Theodore Roosevelt --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com