These emails are getting really long.  Let's try this:  I'll restate  
what I think you're recommending, you correct any as necessary, and  
we'll see if that can make the discussion a bit more succinct.  I'll  
then heavily trim your email and respond to the points that I think  
are particularly comment-worthy.

My main conclusion here, though, is that you're talking about a  
language that bears not a lot of resemblance to Puppet, in the end,  
and if this is something you want, then I recommend starting by  
essentially forking Puppet's parser and working from there.  Either  
that, or trying to turn the current DSL.rb into the language you want,  
although obviously it's pure ruby.

I'm not saying you shouldn't do these things, just saying that you're  
talking about drastic changes to the core of the language for what I  
see as questionable benefit.

On to specifics:

Removal of 'class' and 'node':

Node, class, and define are all merged into a single syntactical  
element.  This element is effectively equivalent to the existing  
'define' element, in that it accepts parameters and is unique only for  
a given name.  That is, you can always create a new instance of this  
element, as long as you give it a different name.  When used with no  
name, the name is automatically set to the name of the element itself.

Node becomes a builtin resource type:

I'm a bit unclear on this.  You mention this as a way to continue  
providing an automatic entry point for compiling, and you make  
reference to turning the facter variables into node attributes.  I  
don't understand this well enough to know how it'd even work.

'include' goes away:

One no longer includes classes, and instead classes are specified  
using the normal resource-specification syntax.  I'm pretty unclear on  
how you'd do this for the typical what-we-currently-call-classes, with  
no unique name and no parameters.  Would it be:

   webserver { : }

Or maybe:

   webserver { webserver: }

This is actually how Puppet started, and I got rid of it because of  
how obviously unobvious they are.

You also say something about relationships being used instead of  
'include', so I assume you mean there that specifying a relationship  
to a class would automatically evaluate that class.

Introduction of the keyword 'self':

I actually don't know what you're doing here, but you're using it in  
all of your examples, so I figured I'd point it out.

Templates become resources:

Move templates from a function to a resource to avoid implicit  
consumption of variables.  I assume this would involve modifying  
properties to know how to retrieve a template's content when  
necessary.  I.e., you'd need to do something like:

   template { "whatever": foo => bar }
   file { "/my/file": content => Template[whatever] }

You'd need to do this for every property, otherwise you'd lose the  
current ability of using templates for any rvalue.

Okay, now for specific (hopefully short) commentary:

On Nov 4, 2008, at 10:09 PM, Florian Grandel wrote:
>
> #
> # We use inheritance here but that's not necessary, we could
> # also use a "mix-in" bundle that is simply included or
> # "required" by other bundles.
> bundle base-node inherits node {
[...]
>
> }
>
> # Define a resource-bundle that represents a
> # web-server node
> bundle super-duper-webserver-node inherits base-node {
[...]
>
> }
>
> # Now let's instantiate our nodes
> super-duper-webserver-node {
>   "myhost1": ;
>   "myhost2": ;
>   ...
> }

Does this mean that we could have multiple subinstances or whatever  
you call them for a given node?  That is, we could have webserver  
{ mynode: } and dbserver { mynode: }?

Also, where are facts here?  You've mentioned making them no longer  
global constants, but I don't know where they went.

> You see in my example that "node" is no longer something special. It
> probably is a built-in "resource-bundle" like "package", "file" or
> whatever that provides read-only instance attributes rather than using
> global facter variables that miraculously appear from "nowhere". (This
> shows the point about read-only attributes that I made in my  
> response to
> the other thread.) Internally facter may provide such attributes, but
> does the user have to be concerned with such implementation detail???

I don't know if you're giving too much or too little credit to the  
Puppet user, but trust me, where those facts come from and how they  
become available in the language is not just an implementation  
detail.  It's a critical part of the framework, and most users end up  
needing to understand it very well, and I don't see anything in your  
recommendation that's changed that.

>
> The only difference is that now "classes", "definitions", "types" and
> "nodes" can all be inherited, parameterized, expanded and whatever,  
> all
> the same without any "artificial" distinctions that have to be  
> learned.
> I think that this one syntax for all is really much easier to  
> understand
> and learn for everybody. You hide away a lot of complexity.

This seems to be the crux of your argument -- that removing  
syntactical variety is simpler and hides complexity -- but I'm not  
convinced.  Puppet's simplicity largely comes from its lack of options  
or complexity -- would you say LISP is simpler or more complex than  
Puppet?  One could argue either way, but I tend toward thinking its  
simplicity makes it potentially more complicated to use.  Certainly it  
raises the bar for the programmer who would be involved.

>
> I personally don't believe that a sysadmin "intuitively" thinks about
> classes and definitions. To the contrary: The fact that you have to
> dedicate a own chapter in the documentation and answer many IRC
> questions about when to use classes and when to use definitions  
> seems to
> show that the distinction is not really intuitive. I personally think
> it's more intuitive to do away with it. Maybe you should start some  
> kind
> of poll for first time users?

Having spent the last three months attempting to teach my infant  
daughters how to nurse, I'm not a big believer in intuitiveness.   
Declarative languages aren't intuitive, modeling resources instead of  
files isn't intuitive, asynchronous administration (i.e., commit and  
wait) isn't intuitive; yet people have learned all of these and  
wouldn't give them up, in most cases.

>
> I think its obvious however that the "bundle-syntax" is as readable as
> the current language but at the same time easier to refactor and  
> expand.

I think you are missing a lot of corner cases (or maybe not-so-corner)  
that make it less so.  In particular, the common case of a "class"  
with no name or parameter is particularly jarring syntactically:

   webserver { : }

For the record, if you look at the earliest versions of Puppet, the  
'include' function was just a shortcut for exactly this syntax.

This gets silly on relationships, too; do I do:

   require => Webserver[]

or:

   require => Webserver[webserver]

or what?

[...]
> Give me some examples of use-cases where you think you cannot do  
> without
> multiple includes or where the "resource-bundle" syntax would be
> counter-intuitive and I'll see whether I have an error in my logic or
> whether I can formulate your use-cases in a satisfactory way in  
> "bundle
> syntax".

You haven't made it explicit, but I assume you mean that specifying a  
relationship to a class would result in automatic evaluation.  That  
is, I could say 'require => Webserver[foo]' and it would automatically  
evaluate that class?  Or would I need to evaluate it elsewhere in  
order to specify a relationship?

>
>> nodes have
>> automatic entry points (i.e., the parser accepts a request from a  
>> host
>> and uses the host's name to look up a node instance).  Neither  
>> classes
>> nor definitions have automatic entry.
>
> The built-in resource-bundle "node" continues to be an automatic entry
> point for puppetd. But IMO that's an unnecessary implementation detail
> that can be hidden away from the user.

Again, I don't think this is an implementation detail -- it's a  
fundamental aspect of how information enters Puppet, and it's  
something users really need to undestand.

>
>> To me, the term 'class' is a convenient way to describe the
>> configuration associated with a given intent.  "Web server" means one
>> list of resources, "dns client" means another, etc.
>
> There are many places where the difference between an "intent" and a
> "resource" is blurred:
> - Is a webserver a resource or an intent?
> - Is a subversion server a resource or an intent?
> - If I have to add a second database instance to my database server,  
> is
> my "database-server class" now suddenly mutating from an intent  
> towards
> a resource?

It seems pretty simple: you must be a database server in order to run  
database instances.  Classes define a service that you provide, and  
resources are some aspect of that service.

[...]
> Now comes my point about "clusters" or "class of nodes". In the
> generalized "bundle-syntax" you can say:
>
> bundle full-system-cluster($needs_firewall = true) {
>   if $self::needs_firewall {
>     firewall-and-load-balancer-node { "${self::name}-fw": }
>   } else {
>     load-balancer-node { "${self::name}-lb": }
>   }
>
>   webserver-node {
>     "${self::name}-web1": ;
>     "${self::name}-web2": ;
>   }
>
>   application-server-node {
>     "${self::name}-app1":
>     "${self::name}-app2":
>   }
>
>   db-server-node { "${self::name}-db": }
> }
>
> And now you can instantiate whole clusters with the same  
> infrastructure
> of containing nodes:
>
> full-system-cluster {
>   "production-cluster": ;
>   "staging-cluster": ;
>   "development-cluster": needs_firewall => false;
> }
>
> You'd effectively configure 18 hosts (three groups of six) in just  
> three
> lines. Isn't that super readable and intuitive, and clearly showing
> intent? Try to express the same thing with disparate node declarations
> (in a .pp file or as external nodes) and you'll have duplicated code
> and/or data en masse.
>
> That's what I meant with "node instances". Sure, puppetd will still
> "enter" at the node level. But why not going down /and/ up in the
> hierarchy to find out about how to configure our specific node? You
> could still derive one single catalog per node.

I don't think I understand this at all.  Given a node name, how does  
it know that it's a part of the system cluster?  If it's part of the  
cluster, how does it know which services from the cluster it provides?

AFAICT, I could do this exact thing with Puppet's classes right now.

>> the lack of meaningful distinction [between node and class] is one
>> thing that led me to want to push nodes outside of Puppet.
>
> You can continue to do so. I believe that the more generic "bundle
> syntax" will help you to simplify and extend your "external definition
> provider" implementations. You could provide external parameters not
> only on type and node level but also in between or above wherever you
> like in the bundle hierarchy. All instantiation can be done  
> externally.
> You could keep only bundle definitions in your *.pp files and get all
> the rest from an external source.

This seems to be pretty far out -- the current interface to external  
nodes is very simple, and it sounds like you're talking about a pretty  
dramatic enhancement to this external interface.  I'd say leave that  
discussion as a separate problem entirely.

[...trying to hurry to actually finish this email...]
>> I don't like the idea of declaring class membership via the same
>> syntax for specifying resources, partially because I think most  
>> people
>> will find that the attributes that are consumed by a class are often
>> specified in a different location than the code that specifies class
>> membership.
>
> Can you give an example? I don't understand that. IMO separating
> parameter and class instances is a design error. This is exactly what
> makes code error prone and difficult to maintain as it increases the  
> the
> amount of code you have to consider when refactoring classes.

I can't come up with much in terms of specific examples right now, but  
I'm kinda short on time.  We can effectively ignore this discussion,  
except that I'm already planning on building a web interface that  
would make it easy to configure nodes and their classes; this  
interface would want to query a class to see what parameters are  
required and then require that those params be filled in on the  
external node tool.  This is a clear separation, and you'd clearly  
want it -- I don't want to have to explicitly import those params or  
something for the node.

>
> If you have to nest bundles at several levels then I consider it good
> practice to re-declare required parameters at every level:
>
> bundle shorewall::rule($ip, $port, ...) {
>   ...
>   file{...template(...using $self::ip and $self::port...)...}
>   ...
> }

As an aside, where is this '$self' stuff from?  You haven't explicitly  
mentioned it, but it seems to be in all of your examples.

[...]
> And one final idea concerning templates:
>
> If you made templates a built-in "resource bundle" rather than a
> function it would be very easy to explicitly declare parameters.
>
> You could simply say:
>
> template { "/my/template.erb": var1 => ..., var2 => ... }
>
> All variables not explicitly declared will simply not be present in  
> the
> template.
>
> This would remove the last occurrence of undeclared dependencies. I
> don't see why you couldn't use ruby's template engine internally  
> anyway.

As mentioned at the top, this would require teaching the Parameter  
class how to understand template instances.  I guess I'm not entirely  
opposed to this, but it seems a bit unnecessary, at the same time.

-- 
Censorship, like charity, should begin at home; but, unlike charity, it
should end there. --Clare Booth Luce
---------------------------------------------------------------------
Luke Kanies | http://reductivelabs.com | http://madstop.com


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to