On 2014-07-01 17:14, Henrik Lindberg wrote:
On 2014-01-07 8:52, David Schmitt wrote:
On 2014-06-28 16:54, Henrik Lindberg wrote:
...
What we want to do:
---

* Make application of defaults eager so that when a resource is
instantiated, it will immediately get the registered and visible
defaults (for missing attributes), at *that* point of time in the
evaluation. This means that defaults become imperative (like variable
assignment).

Do I understand this correctly, that after

   File { mode => 0664 }
   file { "/tmp/foo":; }
   File { owner => bin }
   file { "/tmp/bar": mode => 0755; }

the actual resources will look like

   file {
     # receives mode from first, but not owner from second
     "/tmp/foo": mode => 0644, owner => root;
     # locally defines mode, but gets owner from second
     "/tmp/bar": mode => 0755, owner => bin;
   }

Yes, that is the idea.

and later trying to override any of those attributes (e.g. in a
inherits) will fail?

There are two situations for overrides using Resource Override (i.e.
File['tmp/foo'] { ... => ... }). In general, only unset attributes can
be overridden. Unsure if it is allowed currently to override a set
attribute in an inherited class (need to investigate).

John seems to have done more reading on this topic. If it turns out to be true that subclasses can change already set attribute values (at least +> will do so anyways), the Foo[x][y] is already in a deep hellhole of undefinedness and evaluation order dependency.

* When resource defaults are applied eagerly they are also available when doing collection (instantiation is naturally done before collection
- otherwise there is nothing to collect).

There should be no difference between

   File { mode => 0644 }
   File <| title == 'example' |>

and

   File <| title == 'example' |> { mode => 0644 }

except, perhaps that the latter could create an error when mode is
already set on @file ?

The current implementation allows any attribute to be set, even those
that are already set. The principle seems to be that immutability
kicks in when a resource is realized.

So, the two cases you show would not be equivalent. The first would set
mode to '0644' for File[example] if it was not already set, and the
second would enforce that it was set to '0644'.

Hmmm ...

@file { "/tmp/fail": content => '', tag => [ 'example1', 'example2' ]; }
    File <| tag == 'example1' |> { mode => 0644 }
    File <| tag == 'example2' |> { mode => 0755 }

puppet (apply, 3.1.1) will create /tmp/fail with 0755. Changing the order of the two collectors changes the mode of /tmp/fail.


* There are edge cases where collection can be made at a point where all resources that the query matches (will match) have not yet been created
(i.e. if the virtual resources are instantiated after the query is
evaluated). There seems to be logic that tries to find everything
(lazily at the end), but it is uncertain that it actually works
correctly in all cases. What we propose for the defaults have no effect
on this, it only changes what the resource attributes are when
collecting.

Seems obvious when applying defaults immediately.


* We want to change the function 'defined' to return the state of the
resource instead of just a boolean. Currently the concept of being
"defined" is vague, the function returns true for all kinds of resources
(virtual and exported) as well as those that are included in the
catalog. We want to return some kind of status (that is "truthy" to make
it backwards compatible), but that also tells if the resource is
actually realized (in the catalog). (We agree that using the defined
function is bad practice, but it is required to support certain
use-cases that would otherwise be very painful/impossible to handle).

I think the most common use for "defined" is "is this resource already part of the catalog up until now". I'm not totally sure why you want to burden the Defaults story with *this* can of worms, but I think it might be clearer to deprecate defined in its current form and replace it with
specific functions that inspect the current compilation state.

Now, the function lies - it says that virtual (unrealized) resources are
also "in the catalog", which is not really true. (The concept of
being "defined" is very loosely, uhm... defined)

I'm not saying it shouldn't be fixed (probably 4.0 is a good target to do so; creating warnings for the "wrong" cases in 3.7). I'm just saying that I don't see the connection to resource defaults.

* The File[foo][mode] syntax for lookup of a resource attribute will be more sane, as it will correctly produce the value at that point in time in the evaluation. It is either the value (explicit or default) that will end up in the catalog for a realized resource, or the explicit or
default value of an unrealized virtual resource that *may* get a
different value when it is later realized (if realized at all). Thus, with a combination of being able to know if a resource is realized or not, it is possible to also be certain that the value is the value that
will end up in the catalog).

Even if it's not realized yet, the value can only change iff the current value is undef, yes? In that case, I'd start with making accesses und undef values on not-yet-realized resources invalid. Perhaps even detect when a evaluation-order dependent value is accessed *after* it already
has acquired a value.

If unrealized, the value can change when the resource is realized. A
realized resource attribute cannot be changed. An undef realized value
can change.

Sorry, but I don't quite understand what you were saying about making
access invalid. Can you elaborate?

I was trying to say that when an attribute accessor would fail when accessing still-mutable values, it would not silently switcharoo values when the evaluation order changes. If on the other hand an attribute access would change between an actual value and undef or some not-yet-overwritten default depending on evaluation order, that would be a reason to ban its usage from most systems.

Given the weak immutability (ha!) of attributes as shown in my example above, attribute accessors are already very dangerous.

* In case you wonder, the ability to lookup an attribute is available server side, when the catalog is produced. Later default values set by the agent cannot (for obvious reasons) not be computed when the catalog
is being compiled.

When/how does the agent apply defaults to resources? Have you ment "the
state the agent reads from the running system"?

yes, the agent, when the catalog is applied to the node triggers
logic in types and providers that may "set defaults" depending on the
state of the system where it is running.

That would be Puppet::Type#newtype#newproperty#defaults_to logic then? I would consider types whose defaults_to implementation acts differently on the master and the agent as Very Special[tm] and dangerous. The default provider being a striking counter example of course.

We believe that the construct with lazy default application was required when dynamic scoping was available, but we are honestly not sure about
the rationale behind the current design. There are plenty of
logged issues in Redmine regarding defaults, and collection, but that did not help us much as they are for a variety of versions, and for when dynamic scoping was available (plus a number of other issues where not
fixed), so it is very hard to tell which of the old issues that are
still relevant.

If you are doing advanced things with virtual resources, or advanced composition of defaults where you explicitly depend on the evaluation order, etc. to get the default values you want we would like to hear from you, or naturally if you have input on any of the above. Also if you have logged / or know details of relevant issues that can still be
replicated, we also want to hear from you.

Another thing I'm avoiding, because it didn't work when I started with
export/collect, which you might want to look into:

   define hell($content = $::hostname) {
     file { "/tmp/$::name": content => $content; }
   }

   node b {
     @@hell { $::hostname: }
   }

   node b {
     Hell<<||>>
   }

will create /tmp/a with the content "b", although I would have expected
the content to be "a" too.


Not sure I follow, where would the "a" come from? There is no
exported resource of type Hell when the node is named 'a' (??)

Aggg. The first node should have been called 'a':

Another thing I'm avoiding, because it didn't work when I started with
export/collect, which you might want to look into:

   define hell($content = $::hostname) {
     file { "/tmp/$::name": content => $content; }
   }

   node a { # fixed
     @@hell { $::hostname: }
   }

   node b {
Hell<<||>> # Hell['a']'s $content's default "$::hostname" is evaluated locally as 'b'
   }

will create /tmp/a with the content "b", although I would have expected
the content to be "a" too.


.
.
.



A different idea to reduce the scope of the problem: Decouple the defaults discussion from the bog of other undefined behaviour by moving default setting to a very strict localized syntax:

  file {
      mode => 0321,
      owner => weird;
    "/tmp/foo": content => 'foo';
    "/tmp/bar": content => 'bar';
  }

could be a shorthand for setting those attributes separately on all files in this block. That would make it immediately obvious, that those defaults have a very limited scope and are applied before the closing brace of the file{}. They become syntactically "atomic". They cannot leak to other files in the same class by scrolling off someone's mind. They cannot interfere with collection. The old syntax can be handled separately for compatibility.


That doesn't change that all the other mutability/evaluation-order/parse-order problems around collection and overriding may have to be addressed, but it would decouple the problems.






Regards, David

--
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/puppet-dev/30a8f3465cf0518c006684fade8bfff3%40hosting.edv-bus.at.
For more options, visit https://groups.google.com/d/optout.

Reply via email to