an email to puppet-dev+unsubscribe@googlegroups.com<mailto:puppet-dev+unsub...@googlegroups.com>.
<https://groups.google.com/d/msgid/puppet-dev/CANhgQXu3HVrWJrTnMgYvbY6%3DR8B%3DvVgts2Uqmwjtj6eJRJsH7g%40mail.gmail.com?utm_medium=email&utm_source=footer>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/puppet-dev/CANhgQXu3HVrWJrTnMgYvbY6%3DR8B%3DvVgts2Uqmwjtj6eJRJsH7g%40mail.gmail.com
--
Visit my Blog "Puppet on the Edge"
http://puppet-on-the-edge.blogspot.se/
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/lqsaff%2438h%241%40ger.gmane.org.
On 2014-25-07 3:32, Spencer Krum wrote:You mean like this?
I'm not sure if this is the correct time to mention this, but I wonder
if you considered arrays of hashes in decision eight?
I guess they are not really arrays of hashes but whatever this is:
[
'/root/file1' => {'owner' => 'root'},
'/root/file1' => {'owner' => 'nibz'},
]
Right now we often use arrays of hashes with the create_resources
function when we need to specify parameters. This is similar to the
effect of how arrays passed into resources as title behave.
I think it would be awesome if we could pass what we currently pass into
create_resources into resource instantiations.
$x = [file { $x: }
'/root/file1' => {'owner' => 'root'},
'/root/file1' => {'owner' => 'nibz'},
]
When we discuss this, we preferred that the iteration is made explicit. You can use the same data structure, and do this:
$x.each |$title, $attributes| { file { $title: * => $attributes } }
Since that is much more descriptive. (In fact, that is pretty much what the implementation of create resources is).
- henrik
Thanks,
Spencer
On Thu, Jul 24, 2014 at 6:04 PM, Henrik Lindberg
To view this discussion on the web visit
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/lqtj6g%24png%241%40ger.gmane.org.
DECISION SEVEN AND 3/4On 2014-25-07 2:32, Andy Parker wrote:
DECISION SEVEN
undef is not allowed as a title
Not much to say here. notify { undef: } fails (or anything that
evaluates to undef)
A title expression must result in a String value, or Array of String values. No regular expressions, hashes, booleans, numbers etc.
No magic turning a title into a string if it is not.
an...@puppetlabs.com <mailto:an...@puppetlabs.com>
--
Andrew Parker
*Join us at PuppetConf 2014 <http://www.puppetconf.com/>, September
Freenode: zaphod42
Twitter: @aparker42
Software Developer
22-24 in San Francisco*
/Register by May 30th to take advantage of the Early Adopter discount
<http://links.puppetlabs.com/puppetconf-early-adopter> //—//save $349!/
--
You received this message because you are subscribed to the Google
Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to puppet-dev+unsubscribe@googlegroups.com
<mailto:puppet-dev+unsub...@googlegroups.com>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/puppet-dev/CANhgQXu3HVrWJrTnMgYvbY6%3DR8B%3DvVgts2Uqmwjtj6eJRJsH7g%40mail.gmail.com
<https://groups.google.com/d/msgid/puppet-dev/CANhgQXu3HVrWJrTnMgYvbY6%3DR8B%3DvVgts2Uqmwjtj6eJRJsH7g%40mail.gmail.com?utm_medium=email&utm_source=footer>.
For more options, visit https://groups.google.com/d/optout.
--
Visit my Blog "Puppet on the Edge"
http://puppet-on-the-edge.blogspot.se/
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/lqsaff%2438h%241%40ger.gmane.org.
For more options, visit https://groups.google.com/d/optout.
Howdy,Henrik, David, Erik, John, and others have been having some pretty epic conversations around resource expressions, precedence, order of evaluation, and several other topics. What kicked all of that off was us looking for some feedback on decisions we were making for the Puppet 4 language about how resource overrides, defaults, and so on actually work (or don't in some cases). I think we've finally reached some decisions!Henrik took all of the ideas and started trying to work out what we could do and what we couldn't. Those are in a writeup at https://docs.google.com/a/puppetlabs.com/document/d/1mlwyaEeZqCfbF2oI1F-95cochxfe9gubjfc_BXjkOjA/edit#Lots of information in there, so here is the summary.The principles behind the decisions:1. Only make changes that have a high likelihood of *not* needing to be backed out later.2. Strict or explicit is better than lax or implicit. It uncovers issues and keeps you from lying to yourself.3. Puppet 3 has already stacked up a lot of changes. Do not break manifests unless we really have to.4. Let's not break manifests and then have to break them in almost the same way once we start working on a new catalog system.
There are three kinds of resource expression that we have to deal with:1. Resource instantiation2. Resource defaults3. Resource overridesLooking forward, I think it is highly likely that the catalog system that we'll be working on during puppet 4 will be some sort of production (rules) system. In that kind of a world, resource instantiation likely remains as is, but defaults and overrides will end up having to change quite a bit, if not in syntax, at least in semantics.DECISION ONEResource defaults and Resource overrides will be left untouched.Decision one follows from principles 3 and 4. In the discussions it became clear that changing when defaults or overrides are applied, the scope of defaults, or anything else about them was going to cause a lot of problems. Puppet's master branch changed resource defaults to follow the same scoping rules as variables. That change will be reverted.
DECISION TWOResource instantiations are value producing expressions
QUESTION: should the value always be an array of references? That would make it much more predictable.
DECISION THREEResource instantiation expressions will not be allowed in dangerous locationsOnce resource expressions can be placed anywhere there are a few places where they would actually just do more harm than good (principle 2). One example is as a parameter default (define a($b = notify {hi:}) {}).
DECISION FOURThe LHS of a resource *instantiation* expression can be an expressionWhat?!? This means you can do:$a = notify$a { hi: }Once again, in clearing up odd cases in the grammar this is opened up to us. This is a very powerful feature to have available. Since this is very useful and fits well into the grammar I don't see this being a temporary thing that would then have to go away later (principle 1).
DECISION FIVE (how many of these are there?)A resource with a title of default provides the default parameter values for other resources in the same instantiation expression.Thanks to David Schmitt for this idea!
DECISION SIXThere will be a splat operator for resource instantiation expressionsTo make the default resources (decision five) really useful there needs to be a way to reuse the same values across multiple defaults. The current, dangerous, semantics of resource default expressions skirt this issue by making defaults part of the (dynamic) evaluation scope. In order to make the default resources nearly as useful but much safer, we need to add a way to allow reuse of defaults across multiple resource instantiation expressions explicitly (principle 2).$owner_mode = { owner => andy, mode => '777' } # gotta make it securefile { default: *=> $owner_mode;'/home/andy/.bashrc': ;'/home/andy/.ssh/id_rsa': ;}file { '/etc/passwd': *=> $owner_mode }
DECISION EIGHTAn array as a title expands to individual resource instantiation expressions with titles of the elements of the array.This isn't really too far off from the current semantics, no real change here.
On Thu, Jul 24, 2014 at 6:04 PM, Henrik Lindberg <henrik....@cloudsmith.com> wrote:
DECISION SEVEN AND 3/4On 2014-25-07 2:32, Andy Parker wrote:
DECISION SEVEN
undef is not allowed as a title
Not much to say here. notify { undef: } fails (or anything that
evaluates to undef)
A title expression must result in a String value, or Array of String values. No regular expressions, hashes, booleans, numbers etc.
No magic turning a title into a string if it is not.
I agree in principle, but am worried about the impact. Right now it is somewhat common to do things like:# bad example but should illustrate the ideadefine hosts() {host { $title[hostname]: ip => $title[ip] }}hosts { [{ hostname => andy, ip => '192.168.12.3' },{ hostname => henrik, ip => '192.168.12.4' }]: }This ends up creating instances of Hosts with hashes as titles. Often this works out fine...just not always.
Howdy,Henrik, David, Erik, John, and others have been having some pretty epic conversations around resource expressions, precedence, order of evaluation, and several other topics. What kicked all of that off was us looking for some feedback on decisions we were making for the Puppet 4 language about how resource overrides, defaults, and so on actually work (or don't in some cases). I think we've finally reached some decisions!Henrik took all of the ideas and started trying to work out what we could do and what we couldn't. Those are in a writeup at https://docs.google.com/a/puppetlabs.com/document/d/1mlwyaEeZqCfbF2oI1F-95cochxfe9gubjfc_BXjkOjA/edit#
Lots of information in there, so here is the summary.The principles behind the decisions:1. Only make changes that have a high likelihood of *not* needing to be backed out later.2. Strict or explicit is better than lax or implicit. It uncovers issues and keeps you from lying to yourself.3. Puppet 3 has already stacked up a lot of changes. Do not break manifests unless we really have to.4. Let's not break manifests and then have to break them in almost the same way once we start working on a new catalog system.
There are three kinds of resource expression that we have to deal with:1. Resource instantiation2. Resource defaults3. Resource overridesLooking forward, I think it is highly likely that the catalog system that we'll be working on during puppet 4 will be some sort of production (rules) system. In that kind of a world, resource instantiation likely remains as is, but defaults and overrides will end up having to change quite a bit, if not in syntax, at least in semantics.DECISION ONEResource defaults and Resource overrides will be left untouched.Decision one follows from principles 3 and 4. In the discussions it became clear that changing when defaults or overrides are applied, the scope of defaults, or anything else about them was going to cause a lot of problems. Puppet's master branch changed resource defaults to follow the same scoping rules as variables. That change will be reverted.DECISION TWOResource instantiations are value producing expressionsThe expression based grammar that puppet 4 will be based on changed almost everything into a general expression, which allowed a lot of composition that wasn't possible before. This didn't change resource expressions. Resource expressions could not be assigned ($a = notify {hi:}). That is being changed. This removes several odd corners in the grammar and makes it all more consistent. It is also highly unlikely that it would be removed later (principle 1). The value of a resource expression is a reference to the created resource, or an array of references if there is more than one.QUESTION: should the value always be an array of references? That would make it much more predictable.DECISION THREEResource instantiation expressions will not be allowed in dangerous locationsOnce resource expressions can be placed anywhere there are a few places where they would actually just do more harm than good (principle 2). One example is as a parameter default (define a($b = notify {hi:}) {}).DECISION FOURThe LHS of a resource *instantiation* expression can be an expressionWhat?!? This means you can do:$a = notify$a { hi: }Once again, in clearing up odd cases in the grammar this is opened up to us. This is a very powerful feature to have available. Since this is very useful and fits well into the grammar I don't see this being a temporary thing that would then have to go away later (principle 1).
DECISION FIVE (how many of these are there?)A resource with a title of default provides the default parameter values for other resources in the same instantiation expression.Thanks to David Schmitt for this idea!Since we aren't going to change the behavior of resource default expressions (Notify { ... }) it seems like there needs to be something done to provide a better, safer way of specifying defaults. This will allow:notify {default: message => hi;bye: }The result will be a resource of type Notify with title bye and message hi. It is highly unlikely that this will go away (principle 1) as it is syntactic sugar for specifying the parameters for every resource.
DECISION SIXThere will be a splat operator for resource instantiation expressionsTo make the default resources (decision five) really useful there needs to be a way to reuse the same values across multiple defaults. The current, dangerous, semantics of resource default expressions skirt this issue by making defaults part of the (dynamic) evaluation scope. In order to make the default resources nearly as useful but much safer, we need to add a way to allow reuse of defaults across multiple resource instantiation expressions explicitly (principle 2).$owner_mode = { owner => andy, mode => '777' } # gotta make it securefile { default: *=> $owner_mode;'/home/andy/.bashrc': ;'/home/andy/.ssh/id_rsa': ;}file { '/etc/passwd': *=> $owner_mode }As a side note, do you see what can now be done?$a = notify$b = hi$c = { message => bye }$a { $b: *=> $c }
DECISION SEVENundef is not allowed as a titleNot much to say here. notify { undef: } fails (or anything that evaluates to undef)DECISION EIGHTAn array as a title expands to individual resource instantiation expressions with titles of the elements of the array.This isn't really too far off from the current semantics, no real change here. It is only to call out that we are formalizing that as the semantics. An empty array ends up being a noop (no resources instantiated). An array that contains undef will produce an error (see decision seven). The value default can be an element of the array and will produce the default section for the resources being instantiated (as pointless as that seems since they will all have the same body).DECISION NINEDecisions two through eight do not apply to resource default or resource override expressions.Just to make it clear that decision one still holds.CONCLUSIONI think that covers it all. This will be reflected by a revert to some code, modifying the grammar, adding some new evaluation capabilities, including tests, and updating the specification. All of this is falling under PUP-501, PUP-511, and PUP-2898 in some way shape or form.This email was to record the decisions; make them public; double check that Henrik, Joshua and I all had the same understanding of them; and give another chance to everyone to weigh in.I did have one question that I uncovered as I was writing this up. Some feedback on that would be great as well.--Andrew ParkerFreenode: zaphod42Twitter: @aparker42Software DeveloperRegister by May 30th to take advantage of the Early Adopter discount —save $349!
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/CANhgQXu3HVrWJrTnMgYvbY6%3DR8B%3DvVgts2Uqmwjtj6eJRJsH7g%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
We reasoned that we already have create_resources in frequent use to
solve real issues, so it is needed. I don't think create_resources is
used simply because you can. Instead, it is because you do not
statically know the type, or you want to decide which attributes to set
based on calculations you made. Both of those require create_resources
function. Now it moves into the language.
>
> "*=>" looks weird, even for Puppet. What about contracting it to "*>",
> parallel to the plussignment operator (+>) and to the ordinary value
> binding operator (=>)?
>
The rationale is that you normally have:
name => value
Now, you do not have names, and * is often used as a wildcard/splat/
"split it up", implied, the name is picked from the hash, and you may
want to line them up:
file { default:
* => value ;
foo:
mode => '0777' ;
}
Does that make it feel better?
The first proposal was:
title: (expr)
Then, just use the splat operator:
title: *expr
But then it became weird, because it is a special kind of splat that
applies to the entire expression - that felt more confusing.
>
> DECISION EIGHT
>
> An array as a title expands to individual resource instantiation
> expressions with titles of the elements of the array.
>
> This isn't really too far off from the current semantics, no real
> change here.
>
>
>
> Is there any change /at all/ there with respect to what current Puppet
> already supports? (I don't see any, but you've spooked me.)
>
Current implementation silently skips undef entries, balks at an undef
title (not in an array), but allows other types than Strings as
resulting individual titles (with the weird stringification taking place
that we talked about above). Hence, "not too far off". Feel better now?
Howdy,Henrik, David, Erik, John, and others have been having some pretty epic conversations around resource expressions, precedence, order of evaluation, and several other topics. What kicked all of that off was us looking for some feedback on decisions we were making for the Puppet 4 language about how resource overrides, defaults, and so on actually work (or don't in some cases). I think we've finally reached some decisions!Henrik took all of the ideas and started trying to work out what we could do and what we couldn't. Those are in a writeup at https://docs.google.com/a/puppetlabs.com/document/d/1mlwyaEeZqCfbF2oI1F-95cochxfe9gubjfc_BXjkOjA/edit#Lots of information in there, so here is the summary.The principles behind the decisions:1. Only make changes that have a high likelihood of *not* needing to be backed out later.2. Strict or explicit is better than lax or implicit. It uncovers issues and keeps you from lying to yourself.3. Puppet 3 has already stacked up a lot of changes. Do not break manifests unless we really have to.4. Let's not break manifests and then have to break them in almost the same way once we start working on a new catalog system.There are three kinds of resource expression that we have to deal with:1. Resource instantiation2. Resource defaults3. Resource overridesLooking forward, I think it is highly likely that the catalog system that we'll be working on during puppet 4 will be some sort of production (rules) system. In that kind of a world, resource instantiation likely remains as is, but defaults and overrides will end up having to change quite a bit, if not in syntax, at least in semantics.
Henrik took all of the ideas and started trying to work out what we could do and what we couldn't. Those are in a writeup at https://docs.google.com/a/puppetlabs.com/document/d/1mlwyaEeZqCfbF2oI1F-95cochxfe9gubjfc_BXjkOjA/edit#
Definitely excited to see this stuff moving forwards.According to that doc, syntactically we are transitioning from this:On Thursday, July 24, 2014 5:32:13 PM UTC-7, Andy Parker wrote:Henrik took all of the ideas and started trying to work out what we could do and what we couldn't. Those are in a writeup at https://docs.google.com/a/puppetlabs.com/document/d/1mlwyaEeZqCfbF2oI1F-95cochxfe9gubjfc_BXjkOjA/edit#
* Instantiation notify { hi: message => 'hello' }
* Default Notify { message => 'greetings' }* Override Notify[hi] { message => 'hello there' }
To this:* Instantiation notify { hi: message => 'hello' }
* Default Notify { default: message => 'greetings' }* Override Notify[hi] { default: message => 'hello there' }
This mostly makes sense except for the use of the literal "default" in the Override syntax. The term "default" implies semantics which I don't think are correct. When using an override it's often the case that previously set values are being explicitly swapped out for different ones. It seems like it would make more sense to change the placeholder word to something that reflects that values set take precedence. E.g.* Override Notify[hi] { override: message => 'hello there' }Is it an intentional design decision to continue to use the word "default" in the new syntax for resource overrides?
~Reid--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/1d192839-f8e3-4d0f-a5f8-1c790e96fca0%40googlegroups.com.
DECISION TWOResource instantiations are value producing expressionsThe expression based grammar that puppet 4 will be based on changed almost everything into a general expression, which allowed a lot of composition that wasn't possible before. This didn't change resource expressions. Resource expressions could not be assigned ($a = notify {hi:}). That is being changed. This removes several odd corners in the grammar and makes it all more consistent. It is also highly unlikely that it would be removed later (principle 1). The value of a resource expression is a reference to the created resource, or an array of references if there is more than one.
QUESTION: should the value always be an array of references? That would make it much more predictable.
DECISION FOURThe LHS of a resource *instantiation* expression can be an expressionWhat?!? This means you can do:$a = notify$a { hi: }Once again, in clearing up odd cases in the grammar this is opened up to us. This is a very powerful feature to have available. Since this is very useful and fits well into the grammar I don't see this being a temporary thing that would then have to go away later (principle 1).
As a side note, do you see what can now be done?$a = notify$b = hi$c = { message => bye }$a { $b: *=> $c }
On Thu, Jul 24, 2014 at 5:32 PM, Andy Parker <an...@puppetlabs.com> wrote:
Howdy,Henrik, David, Erik, John, and others have been having some pretty epic conversations around resource expressions, precedence, order of evaluation, and several other topics. What kicked all of that off was us looking for some feedback on decisions we were making for the Puppet 4 language about how resource overrides, defaults, and so on actually work (or don't in some cases). I think we've finally reached some decisions!Henrik took all of the ideas and started trying to work out what we could do and what we couldn't. Those are in a writeup at https://docs.google.com/a/puppetlabs.com/document/d/1mlwyaEeZqCfbF2oI1F-95cochxfe9gubjfc_BXjkOjA/edit#Lots of information in there, so here is the summary.The principles behind the decisions:1. Only make changes that have a high likelihood of *not* needing to be backed out later.2. Strict or explicit is better than lax or implicit. It uncovers issues and keeps you from lying to yourself.3. Puppet 3 has already stacked up a lot of changes. Do not break manifests unless we really have to.4. Let's not break manifests and then have to break them in almost the same way once we start working on a new catalog system.There are three kinds of resource expression that we have to deal with:1. Resource instantiation2. Resource defaults3. Resource overridesLooking forward, I think it is highly likely that the catalog system that we'll be working on during puppet 4 will be some sort of production (rules) system. In that kind of a world, resource instantiation likely remains as is, but defaults and overrides will end up having to change quite a bit, if not in syntax, at least in semantics.Replying to myself...tsk tsk. Oh well.This is to provide an update on what's going on. Henrik put together a bunch of changes to the implementation to carry out these decisions. I worked on the specification to get it to align with these decisionsThe change to the specification happened in this PR https://github.com/puppetlabs/puppet-specifications/pull/14We've already identified one problem in the specification, it doesn't allow nested arrays of strings in the title. I have a note to fix that.
The implementation changes are currently in this PR https://github.com/puppetlabs/puppet/pull/2914I'm working through adding tests based on the specification and to explore what kinds of changes to the current semantics we have got.Joshua and I have been working on putting together some tests to not only test the implementation against the specification, but also to see how different it really ends up being from the old implementation. The tests check several different scenarios, but basically, the first item is used as the title of a resource, the second is whether we expect to create a resource or get an error. The third element is either the regexp for the error message or the titles of the resources that actually get created.This is for the current system:["thing" ,"resource", ["thing"]],["[thing]" ,"resource", ["thing"]],["[[nested, array]]" ,"resource", ["nested", "array"]],
["1" ,"resource", ["1"]], # deprecate?["3.0" ,"resource", ["3.0"]], # deprecate?["[1]" ,"resource", ["1"]], # deprecate?["[3.0]" ,"resource", ["3.0"]], # deprecate?#["true" ,"resource", ["true"]], literal true doesn't parse. true as a variable parses and creates a resource#["false" ,"resource", ["false"]], similar problems to [false] below. literal false doesn't parse["[true]" ,"resource", ["true"]], # this makes no sense given the next case["[false]" ,"error", /No title provided and :notify is not a valid resource reference/], # *sigh*#["undef" ,"resource", ["undef"]], # works for variable value, not for literal. deprecate?["[undef]" ,"resource", ["undef"]], # deprecate?
#["{nested => hash}" ,"resource", ["{nested => hash}"]], doesn't work for a literal hash (syntax error). In a variable it is created, but isn't possible to reference the resource. deprecate?#["[{nested => hash}]" ,"resource", ["{nested => hash}"]], works as both literal and variable, but isn't possible to reference the resource. deprecate?
["/regexp/" ,"error", /Syntax error/],["[/regexp/]" ,"error", /Syntax error/],["default" ,"error", /Syntax error/],["[default]" ,"error", /Syntax error/],The current system has a lot of odd outcomes in it.
Here are the tests for the future parser (as changed by the PR)["thing" ,"resource", ["thing"]],["[thing]" ,"resource", ["thing"]],["[[nested, array]]" ,"resource", ["nested", "array"]],
["1" ,"error", /Illegal title type.*Expected String, got Integer/],["3.0" ,"error", /Illegal title type.*Expected String, got Float/],["[1]" ,"error", /Illegal title type.*Expected String, got Integer/],["[3.0]" ,"error", /Illegal title type.*Expected String, got Float/],["true" ,"error", /Illegal title type.*Expected String, got Boolean/],["false" ,"error", /Illegal title type.*Expected String, got Boolean/],["[true]" ,"error", /Illegal title type.*Expected String, got Boolean/],["[false]" ,"error", /Illegal title type.*Expected String, got Boolean/],["undef" ,"error", /Missing title.*undef/],["[undef]" ,"error", /Missing title.*undef/],["{nested => hash}" ,"error", /Illegal title type.*Expected String, got Hash/],["[{nested => hash}]" ,"error", /Illegal title type.*Expected String, got Hash/],["/regexp/" ,"error", /Illegal title type.*Expected String, got Regexp/],["[/regexp/]" ,"error", /Illegal title type.*Expected String, got Regexp/],["default" ,"resource", []], # nothing created because this is just a local default["[default]" ,"resource", []],I'm a little worried that these changes might be too extreme. Thoughts?
On Tuesday, July 29, 2014 1:23:09 PM UTC-5, Andy Parker wrote:On Thu, Jul 24, 2014 at 5:32 PM, Andy Parker <an...@puppetlabs.com> wrote:
Howdy,Henrik, David, Erik, John, and others have been having some pretty epic conversations around resource expressions, precedence, order of evaluation, and several other topics. What kicked all of that off was us looking for some feedback on decisions we were making for the Puppet 4 language about how resource overrides, defaults, and so on actually work (or don't in some cases). I think we've finally reached some decisions!Henrik took all of the ideas and started trying to work out what we could do and what we couldn't. Those are in a writeup at https://docs.google.com/a/puppetlabs.com/document/d/1mlwyaEeZqCfbF2oI1F-95cochxfe9gubjfc_BXjkOjA/edit#Lots of information in there, so here is the summary.The principles behind the decisions:1. Only make changes that have a high likelihood of *not* needing to be backed out later.2. Strict or explicit is better than lax or implicit. It uncovers issues and keeps you from lying to yourself.3. Puppet 3 has already stacked up a lot of changes. Do not break manifests unless we really have to.4. Let's not break manifests and then have to break them in almost the same way once we start working on a new catalog system.There are three kinds of resource expression that we have to deal with:1. Resource instantiation2. Resource defaults3. Resource overridesLooking forward, I think it is highly likely that the catalog system that we'll be working on during puppet 4 will be some sort of production (rules) system. In that kind of a world, resource instantiation likely remains as is, but defaults and overrides will end up having to change quite a bit, if not in syntax, at least in semantics.Replying to myself...tsk tsk. Oh well.This is to provide an update on what's going on. Henrik put together a bunch of changes to the implementation to carry out these decisions. I worked on the specification to get it to align with these decisionsThe change to the specification happened in this PR https://github.com/puppetlabs/puppet-specifications/pull/14We've already identified one problem in the specification, it doesn't allow nested arrays of strings in the title. I have a note to fix that.
Is support for nested string arrays an intentional current feature? I hadn't thought so, but maybe you slipped in automatic flattening of array titles sometime when I wasn't looking. If it's not a current feature, then does it need to be a future feature?
The implementation changes are currently in this PR https://github.com/puppetlabs/puppet/pull/2914I'm working through adding tests based on the specification and to explore what kinds of changes to the current semantics we have got.Joshua and I have been working on putting together some tests to not only test the implementation against the specification, but also to see how different it really ends up being from the old implementation. The tests check several different scenarios, but basically, the first item is used as the title of a resource, the second is whether we expect to create a resource or get an error. The third element is either the regexp for the error message or the titles of the resources that actually get created.This is for the current system:["thing" ,"resource", ["thing"]],["[thing]" ,"resource", ["thing"]],["[[nested, array]]" ,"resource", ["nested", "array"]],
And that last one actually works? I would have expected this:
["[[nested, array]]" ,"resource", ["nestedarray"]]
, which I don't categorize as "working".
["1" ,"resource", ["1"]], # deprecate?["3.0" ,"resource", ["3.0"]], # deprecate?["[1]" ,"resource", ["1"]], # deprecate?["[3.0]" ,"resource", ["3.0"]], # deprecate?#["true" ,"resource", ["true"]], literal true doesn't parse. true as a variable parses and creates a resource#["false" ,"resource", ["false"]], similar problems to [false] below. literal false doesn't parse["[true]" ,"resource", ["true"]], # this makes no sense given the next case["[false]" ,"error", /No title provided and :notify is not a valid resource reference/], # *sigh*#["undef" ,"resource", ["undef"]], # works for variable value, not for literal. deprecate?["[undef]" ,"resource", ["undef"]], # deprecate?
I'd say of the above that any value that works as a title when specified indirectly via a variable should also work when specified as a literal, and vise versa. I would be ok with requiring actual strings instead of stringifying values of other types. I believe Henrik promoted that approach.
#["{nested => hash}" ,"resource", ["{nested => hash}"]], doesn't work for a literal hash (syntax error). In a variable it is created, but isn't possible to reference the resource. deprecate?#["[{nested => hash}]" ,"resource", ["{nested => hash}"]], works as both literal and variable, but isn't possible to reference the resource. deprecate?
You can't reference the literal because the resource name is not the hash, it is the stringification of the hash. IIRC works out to "nestedhash" in this case. I would be all for deprecating that behavior. As far as I know, it is never used except by mistake, and the errors resulting from that mistake are confusing to the casual Puppet user.
["/regexp/" ,"error", /Syntax error/],["[/regexp/]" ,"error", /Syntax error/],["default" ,"error", /Syntax error/],["[default]" ,"error", /Syntax error/],The current system has a lot of odd outcomes in it.
I'd agree with that, but odd as they are, they are also relatively consistent if you look at it from the right perspective. Mostly the behavior springs from the fact that Puppet expects resource titles to be strings, and from the fact that the grammar recognizes and distinguishes the data types of many productions. There's a bit of a tension there, though, because if you sneak a non-string individual resource title to the back end by, say, hiding it in a variable, then the back end just stringifies it instead of rejecting it.
Here are the tests for the future parser (as changed by the PR)["thing" ,"resource", ["thing"]],["[thing]" ,"resource", ["thing"]],["[[nested, array]]" ,"resource", ["nested", "array"]],
I still find that last one surprising, but if it really matches the current behavior then so be it. What's the rule here, though? Array titles are automatically flattened?
["1" ,"error", /Illegal title type.*Expected String, got Integer/],["3.0" ,"error", /Illegal title type.*Expected String, got Float/],["[1]" ,"error", /Illegal title type.*Expected String, got Integer/],["[3.0]" ,"error", /Illegal title type.*Expected String, got Float/],["true" ,"error", /Illegal title type.*Expected String, got Boolean/],["false" ,"error", /Illegal title type.*Expected String, got Boolean/],["[true]" ,"error", /Illegal title type.*Expected String, got Boolean/],["[false]" ,"error", /Illegal title type.*Expected String, got Boolean/],["undef" ,"error", /Missing title.*undef/],["[undef]" ,"error", /Missing title.*undef/],["{nested => hash}" ,"error", /Illegal title type.*Expected String, got Hash/],["[{nested => hash}]" ,"error", /Illegal title type.*Expected String, got Hash/],["/regexp/" ,"error", /Illegal title type.*Expected String, got Regexp/],["[/regexp/]" ,"error", /Illegal title type.*Expected String, got Regexp/],["default" ,"resource", []], # nothing created because this is just a local default["[default]" ,"resource", []],I'm a little worried that these changes might be too extreme. Thoughts?
Beyond what I've already said, I don't personally have a problem with any of the changes highlighted here.
John
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/76d12bc2-5917-42b9-b397-c5773df8b9fe%40googlegroups.com.
The reasoning given by Henrik for why this should stay around is because you couldn't previously directly concatenate two arrays in the puppet language leading to people possibly doing this, either intentionally or unintentionally:$a = [a, b]$b = [c, d]notify { [$a, $b]: }And of course this kind of a situation can be setup somewhere along a long chain of constructing titles and passing things around, so it is really hard to tell if it is really used or not. I did a check through a large body of puppet code (a dump of the forge modules) and I haven't found anything as explicit as what I have above, but every time I think something isn't done it turns out that there is someone who was doing it.Just to note, that can now be done as:$a = [a, b]$b = [c, d]notify { $a + $b: }Any thoughts on how disruptive it might be to remove this? Or whether this feature is even bad to keep around? It seems pretty harmless to me to just keep it.
And that last one actually works? I would have expected this:
["[[nested, array]]" ,"resource", ["nestedarray"]]
, which I don't categorize as "working".Yep. That one creates two resources with those two titles. I'm willing to change it and be stricter, but I think it comes down to making an argument for why allowing nested arrays is actually *bad*.
#["{nested => hash}" ,"resource", ["{nested => hash}"]], doesn't work for a literal hash (syntax error). In a variable it is created, but isn't possible to reference the resource. deprecate?#["[{nested => hash}]" ,"resource", ["{nested => hash}"]], works as both literal and variable, but isn't possible to reference the resource. deprecate?
You can't reference the literal because the resource name is not the hash, it is the stringification of the hash. IIRC works out to "nestedhash" in this case. I would be all for deprecating that behavior. As far as I know, it is never used except by mistake, and the errors resulting from that mistake are confusing to the casual Puppet user.
It works:> be puppet apply -e '$a = { my => hash } notify { $a: } notify { second: require => Notify[{"my"=>"hash"}] }'Notice: Compiled catalog for aparker.corp.puppetlabs.net in environment production in 0.02 secondsNotice: {"my"=>"hash"}Notice: /Stage[main]/Main/Notify[{"my"=>"hash"}]/message: defined 'message' as '{"my"=>"hash"}'Notice: secondNotice: /Stage[main]/Main/Notify[second]/message: defined 'message' as 'second'Notice: Finished catalog run in 0.06 seconds
And it works in a surprising number of situations. The title of the resource ends up being the hash:
{"type": "Notify","title": {"my": "hash"},"tags": ["notify","class"],"file": "/Users/andy/work/puppet/t.pp","line": 2,"exported": false,"parameters": {"name": "{\"my\"=>\"hash\"}"}}The name parameter ends up being a stringification of the hash and edges it is also a stringification:{"source": "Class[main]","target": "Notify[{\"my\"=>\"hash\"}]"}This can sometimes go wrong (https://tickets.puppetlabs.com/browse/PUP-2935 <- I haven't figured out what happened there other than using a hash as a title going awry).
Exactly. And that is why I'm a little nervous about just disallowing all of these types. However, it will now fail fast and so the migration path to the new system is: get rid of warnings, run with --parser future, fix errors, check that your systems still work. OTOH what do we lose from just continuing to stringify certain data types?
On 2014-07-31 22:16, John Bollinger wrote:
[good points]
Just a quick note that I'm mainly agreeing with John's points: Automatic (and inconsistent) stringification of non-string-titles is weird and confusing, thus should be avoided. Automatic flattening of arrays-of-strings is weird, but probably not confusing, thus can be allowed, should be documented and discouraged (e.g. point in the docs to explicit flattening).
Regards, David
--
* Always looking for people I can help with awesome projects *
G+: https://plus.google.com/+DavidSchmitt
Blog: http://club.black.co.at/log/
LinkedIn: http://at.linkedin.com/in/davidschmitt
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/53DB4444.9080408%40dasz.at.
On Fri, Aug 1, 2014 at 12:39 AM, David Schmitt <da...@dasz.at> wrote:On 2014-07-31 22:16, John Bollinger wrote:
[good points]
Just a quick note that I'm mainly agreeing with John's points: Automatic (and inconsistent) stringification of non-string-titles is weird and confusing, thus should be avoided. Automatic flattening of arrays-of-strings is weird, but probably not confusing, thus can be allowed, should be documented and discouraged (e.g. point in the docs to explicit flattening).Alright, I'll take that as consensus then (or at least consent).The implementation that is on that branch will remain as is, and the spec will be taken as the final form WRT resource expressions.
On Friday, July 25, 2014 5:15:30 PM UTC-5, henrik lindberg wrote:
We reasoned that we already have create_resources in frequent use to
solve real issues, so it is needed. I don't think create_resources is
used simply because you can. Instead, it is because you do not
statically know the type, or you want to decide which attributes to set
based on calculations you made. Both of those require create_resources
function. Now it moves into the language.
For what it's worth, every use of create_resources() that I have ever come across or thought about has involved a resource type that is statically known. The usual reason for create_resources() is that the identities and properties of the resources need to be dynamically determined. That is, if I need or want to resort to create_resources() then it's usually because I don't know statically which specific resources (of a known type) need to be managed. Sometimes I also don't know which properties need to be managed or maybe what their target values should be, but that's secondary.
The first proposal was:
title: (expr)
Then, just use the splat operator:
title: *expr
But then it became weird, because it is a special kind of splat that
applies to the entire expression - that felt more confusing.
But haven't you still got a special kind of splat? I think all you've done is alter the spelling to distinguish it from the other splat -- which is better than not -- but it's still kinda confusing.
Here are the tests for the future parser (as changed by the PR)["thing" ,"resource", ["thing"]],["[thing]" ,"resource", ["thing"]],["[[nested, array]]" ,"resource", ["nested", "array"]],
I still find that last one surprising, but if it really matches the current behavior then so be it. What's the rule here, though? Array titles are automatically flattened?
[...]
I know this wouldn't cover every case, but wouldn't it cover the majority of cases, and thus be a better trade-off? That is, we have a somewhat less powerful language, but a much more accessible language, and it comfortably covers the 95%+ use cases while still being usable by 95%+ of its users?
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/7BA49B49-5B61-4C2A-8EA4-C431B92811AF%40puppetlabs.com.
For more options, visit https://groups.google.com/d/optout.
My main objection with create_resources function is that it is not a
natural progression from the language. When developing puppet code, you
start out with simple resources and use the syntax for creating them. As
you are building up your modules and complexity increases you reach a
point where you have to redo what you have already done because now you
have to instead construct a hash and call a function.
When you have reached this point several times, you are more likely to
always use create_resources.
When instead directly supported in the language, you can add the more
advanced things if and when they are needed.
Having the power to do so, does not take anything away.
- henrik
I am concerned that adding additional operators to the language does in fact take something away. As such, I do think that proposals to do so need to require a very strong argument in order to proceed.When I go out and introduce new teams of sysadmins to Puppet, the fact in vacuo that we have our own domain-specific language is anything but a strength. One of the top initial objections to Puppet today is that large teams will not be able, or will not want, to learn a new, complex language. What sets us apart from competitors like Chef, from scripting alternatives, is the simplicity and apparent intuitive design of our DSL. The fact that it is more akin to a configuration file than to a procedural program. That a sysadmin can look at a Puppet manifest and usually figure out the basics of what it does and even modify it without needing a training course or a pocket reference. Every operator that is added to the language has the potential to take away from that, and so absolutely needs to be approached as a design decision focused on the end-user experience.We need the ability to better transform structured data into resources. From an end-user experience perspective (setting aside implementation considerations) I much prefer the idea of using a hash directly over introducing a new operator. The difference would be the two examples shown below.Proposed operator (proposed):$x.each |$title, $attributes| { file { $title: * => $attributes } }Formal hash treatment (my preferred):$x.each |$title, $attributes| { file { $title: $attributes } }If we introduce a new operator it should be a user-experience design decision, not an implementation decision. If the preferred design cannot be implemented due to technical constraints that's something we have to deal with. But I hope that we're arriving at decisions to introduce new operators as part of an intentional end-user experience focused design.The fact that we have a DSL is not a strength. The fact that it is simple and intuitive to practitioners in this space, is.
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/CAC9eg%2BkFefgHzYJmYU5k9%3DF-EhMj3h3y9O9qNGDQigKpzx0ewA%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/lrp0s2%24c09%241%40ger.gmane.org.
On 2014-05-08 1:08, Trevor Vaughan wrote:The functionality is not limited to the default title, and a literal default is not a special expression so the grammar has no special knowledge. It is basically:
This is certainly better than the new operator but the parenthesis are a
bit strange.
Isn't the title 'default' special enough to not have the parenthesis?
Body : expression ':' attribute_operations ... ;
i.e. you can use it for a titled resource as well:
file { '/tmp/foo': ($hash) }You mean in puppet parser validate? Or where? (You should get static validation of this - it cannot validate that the expression will evaluate to a valid hash though, that is not known until you actually run the code). But maybe you meant something else?
If not, then I can certainly live with the parenthesis syntax better
than a new operator (though support in the syntax checkers will be most
useful).
Regards
- henrik
Thanks,
Trevor
On Mon, Aug 4, 2014 at 6:18 PM, Henrik Lindberg
an email to puppet-dev+unsubscribe@googlegroups.com<mailto:puppet-dev+unsub...@googlegroups.com>.
https://groups.google.com/d/msgid/puppet-dev/CANs%2BFoUGYSACC5OS0vkyZVT6Yz6j2kgaGGphZmis90mWKSYKmA%40mail.gmail.com
To view this discussion on the web visit
<https://groups.google.com/d/msgid/puppet-dev/CANs%2BFoUGYSACC5OS0vkyZVT6Yz6j2kgaGGphZmis90mWKSYKmA%40mail.gmail.com?utm_medium=email&utm_source=footer>.
--
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/lrp48o%24i8b%241%40ger.gmane.org.
The first proposal was:
title: (expr)
Then, just use the splat operator:
title: *expr
But then it became weird, because it is a special kind of splat that
applies to the entire expression - that felt more confusing.
But haven't you still got a special kind of splat? I think all you've done is alter the spelling to distinguish it from the other splat -- which is better than not -- but it's still kinda confusing.Agreed.
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/D4F608CD-67BF-4E4C-BA68-E54BF1A10678%40puppetlabs.com.
So, to summarize: The use of * => as an operator is not liked but the concept of being able to set attributes from a hash is. Unfortunately, it is not possible to directly allow an expression at the position in question, there must be a syntactical marker.
As pointed out earlier, the * => was thought to read as "any_attribute => from_these_values", but I totally grok if people have an allergic reaction.
We can do this though:
file { default: ($hash) }
This works because it is impossible to have an attribute name in parentheses.
In use:
file (
default : ($my_file_defaults + { mode => '0666' });
'/tmp/foo': ;
'/tmp/bar': ;
}
Is that better? No new operator, but you have to use parentheses around the expression.
We can naturally also revert the functionality, but it seems it is liked conceptually.
- henrik
# using parenthesis hash styleclass foo ($servername = $::fqdn,$port = 80,$ssl = false,$extra_opts={},) {apache::vhost { $servername: ($extra_opts + {port => $port,ssl => $ssl,})}}# using * =>class foo ($servername = $::fqdn,$port = 80,$ssl = false,$extra_opts={},) {apache::vhost { $servername:port => $port,ssl => $ssl,* => $extra_opts,}
IMO the *=> is way more readable (as gist here if formatting is screwed up for you: https://gist.github.com/dalen/57b37b80a9ba1879b78c). This is quite similar to what I linked earlier that I am doing in https://github.com/spotify/puppet-puppetexplorer/blob/master/manifests/init.pp#L89-L97So it is not just a contrived example.
--
Erik Dalén
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/CAAAzDLdQv5iC40X0Qpx9pFaEhKf6FBPwf%3DKoLjtO7oDnDVt5bw%40mail.gmail.com.
I like that piece of code as it is. Perhaps I would add a comment noting that $vhost_options is not allowed to override the base_vhost_options and give a reason for that. I needed to browse up to the parameter doc and think a bit about what that should mean.
I do not think the whole sequence would be any better with some kind of special operator, except perhaps for the hash() thingy, which I conveniently ignore in the analysis, but assume it's doing some merging.
Also, create_resources is google-able. To find the splat operator, one would either have to know it or think about the language reference and browse through the visual index or the operator chapter.
On 2014-06-08 3:41, Reid Vandewiele wrote:
On Tue, Aug 5, 2014 at 4:11 PM, Henrik Lindberg
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/lrtbji%24fqe%241%40ger.gmane.org.
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/1d38a4dd-596e-4338-b0d5-f6117f3a6052%40googlegroups.com.
$extra_opts = { $ssl => true, ... }
apache::vhost { ...
ssl => undef,
attributes => $extra_opts,
}
$extra_opts = { $ssl => undef, ... }
apache::vhost { ...
ssl => true,
attributes => $extra_opts,
}
apache::vhost { $title:
...**$extra_opts}
apache::vhost { $title:...&$extra_opts}
apache::vhost { $tilte:...*$extra_opts}
$extra_opts = { $ssl => true, ... }
I assume you mean {ssl => true, ...}, and not the value of a variable $ssl ?
Both of these results in an error, you are not allowed to set ssl twice (most likely a mistake).
apache::vhost { ...
ssl => undef,
attributes => $extra_opts,
}
And:
$extra_opts = { $ssl => undef, ... }
apache::vhost { ...
ssl => true,
attributes => $extra_opts,
}
Example 1 (assuming behavior whereinmerging is OK, and that explicit parameter specification takes precedence):
...
Example 2 (assuming that merging is not OK, and that conflicts will be treated as duplicate parameter specification):
undef only has a special meaning when it is the final value of the given attribute; it then means "No value specified for this parameter".My expectation is that in both cases 'undef' means "pretend I've said
nothing about thus attribute here" and that *true* wins in either case.
That is undef behaves as a "value" until the resource creation takes place.
Exec { timeout => 30 }
# Bunch of execs that sometimes take too damn long
exec { '/usr/bin/sleep 60': }
...
# Then another exec that should have the default timeout, but I don't want# to hardcode (or even remember) what that is (i.e. pretend the above# resource default does not exist):
Or passing options from a defined type to a type declaration:exec { '/usr/bin/ping localhost': timeout => undef }
define filelike($seltype = undef) {
file { '/tmp/foo':
seltype => $seltype,}}
apache::vhost { $title: **$extra_opts }
or:
apache::vhost { $title: &$extra_opts }
or:
apache::vhost { $title: *$extra_opts }
So, that was the initial proposal '*' for any name followed by => and the value. This also looks similar to the unary splat '*' that can be used to unfold an array or hash.
That suggestion was not well liked... "no more operators please...".
It would be possible to specify '*' as signaling "here is an attributes hash". The only quirk is that it would be a special syntactic marker that is followed by any expression (which includes splat) - no harm, just slightly odd that you are allowed to write **$extra_opts, where this is not allowed elsewhere (splat is non associative, just like unary minus).
#less readablefile {default:mode => '0666';'/tmp/foo': ;'/tmp/bar': ;'/tmp/special':mode => '0777';}One would write this:
#more readable$defaults = {ensure => file,mode => '0666',}file { [ '/tmp/foo', '/tmp/bar' ]:attribute_defaults => $defaults,}file { '/tmp/special':mode => '0777',attribute_defaults => $defaults,}The benefits to that approach are that it looks & feels more like the Puppet language, it's less of a conceptual change going forward, and it's also easily searchable. It's also possible have multiple default hash variables in scope and just assign them as needed.
On 2014-07-08 1:18, Wil Cooley wrote:
On Wed, Aug 6, 2014 at 1:30 PM, Henrik Lindberg
an email to puppet-dev+unsubscribe@googlegroups.com<mailto:puppet-dev+unsub...@googlegroups.com>.
<https://groups.google.com/d/msgid/puppet-dev/CAMmm3r5jAUnP0s_rWVqtUqJ4cZjnuCrLLG77XteG0q7rY7W43Q%40mail.gmail.com?utm_medium=email&utm_source=footer>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/puppet-dev/CAMmm3r5jAUnP0s_rWVqtUqJ4cZjnuCrLLG77XteG0q7rY7W43Q%40mail.gmail.com
--
Visit my Blog "Puppet on the Edge"
http://puppet-on-the-edge.blogspot.se/
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+unsubscribe@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/lrugeh%24527%241%40ger.gmane.org.
Visual review, for convenience:file { $title: * => $attributes; }file { $title: => $attributes; }file { $title: ($attributes); }file { $title: attribute_defaults => $attributes; }file { $title: attribute_hash => $attributes; }