Jira (PUP-6322) EPP and scope context

4 views
Skip to first unread message

Brett Gray (JIRA)

unread,
May 18, 2016, 9:34:03 PM5/18/16
to puppe...@googlegroups.com
Brett Gray created an issue
 
Puppet / Improvement PUP-6322
EPP and scope context
Issue Type: Improvement Improvement
Affects Versions: PUP 4.4.0
Assignee: Unassigned
Components: Language
Created: 2016/05/18 6:33 PM
Priority: Normal Normal
Reporter: Brett Gray

Current State

Currently EPP templates do not gain access to variables from the calling context. This is in contrast to ERB templates that do gain access to variables from the calling context.

One good element of ERB templates is that they gain access to variables from the calling class, this makes life easier on the user/developer. Out of scope lookups can be performed if required to ensure facts are correct (e.g. lookups at the correct scope).

In EPP templates the variables must be looked up using the full scope or injected via parameters.

The nice thing about EPP templates is that the user/developer do not need to know about Ruby at all and can just use Puppet, but the need to perform full path lookups of variables is painful, especially as most templates are used within modules, therefore they will not normally be called from classes in other modules.

The nice thing about ERB templates is that they gain access to all variables in the scope of the calling class, but you have to possibly have to understand some Ruby and that once again we use a different symbol for variables.

The differences between the two templates styles, forgetting the actual language, is that they gain access to variables via different methods. This causes confusion with users and developers, especially when they are new to Puppet.

Proposal

I propose that we change the behaviour of EPP templates and allow them to gain access to the variables of the scope of the calling class. This will provide more consistency in the product and be easier for new users of Puppet to learn. This will also provide EPP templates with the advantage of having all variables available in the calling class and therefore be simpler for users.

Add Comment Add Comment
 
This message was sent by Atlassian JIRA (v6.4.13#64028-sha1:b7939e9)
Atlassian logo

Geoff Williams (JIRA)

unread,
May 18, 2016, 9:36:04 PM5/18/16
to puppe...@googlegroups.com
Geoff Williams commented on Improvement PUP-6322
 
Re: EPP and scope context

Gets my vote. Keep things simple and reduce the amount of typing needed

Jesse Reynolds (JIRA)

unread,
May 18, 2016, 11:59:03 PM5/18/16
to puppe...@googlegroups.com

Agree. Fully qualifying variables in templates is painful.

Is the counter-argument that it's good practice to fully qualify your variables in templates? ... If you have good layout you know what the calling class based on the directory structure containing the template, so there should be little room for confusion about scope / namespace.

As a puppet coder who's written erb templates before, it's natural to expect that the template will be executed in the same context as the calling puppet code, no matter if you're using EPP or ERB.

Henrik Lindberg (JIRA)

unread,
May 19, 2016, 1:24:08 PM5/19/16
to puppe...@googlegroups.com

Have to think about this as it is like calling an external function and that function has access to all your local variables. That is truly horrible and it leads to problems like not being able to reuse templates. It is unspecific, not robust, not type safe, impure, (I can go on about this). It is ok for inline epp as it works like a lambda, it is embedded in the context it gets variables from. With external EPP from a file it is like an external function.

I do recognize the pain and I would like to help making it easier as you now manually have to assemble all variables and give them to the template - or access them via fully qualified names.

Note that there is new syntax that makes it easy to import a bunch of names at the same time from another namespace.

[$param1, $param2, $param3] = Class[foo::bar::fee::fum]

Would give you local variables $param1... etc. from $foo::bar::fee::fum::param1, $foo::bar::fee::fum::param2, etc.
Which saves a lot of typing.

Ideally, a template should not pull anything at all from anywhere and only rely on what is given to it, and its parameters should be declared and typed. Then instead of empty strings, wrong data type, etc. will be caught automatically instead of just the "wrong text" being produced.

Currently you have to supply arguments as a hash. Maybe we can do something about that so that becomes easy(er/ish).

You can always do this:

class foo($a= 10, $b=20) {
}
include foo
notice inline_epp(@(EPP), {context => Class[foo]})
<% |Type[Class[foo]] $context | %>
 $a = <%= $context[a] %>
 $b = <%= $context[b] %>
EPP

This uses an inline EPP, but done such a way that it works for an external file as well.

  • The EPP defines a parameter $context, and it types it so it only accepts Class[foo]
  • It then uses $context[param] to get the parameters from the class (this works for resources as well)
  • When calling the template, a reference is sent to the class.

This works if:

  • only accessing the class/resource parameters and not any other variables.

To also mix in variables, add them to the hash in a fitting maner.

IMO, the "multi assign" works best - here is an example that shows that in an EPP

class foo($a= 10, $b=20) {
 $var = 100
}
include foo
notice inline_epp(@(EPP), {context => Class[foo]})
<% |Type[Class[foo]] $context | -%>
 <% [$a, $b, $var] = $context %>
 $a = <%= $a %>
 $b = <%= $b %>
 $var = <%= $var %>
EPP

That I think is the current best (and safe) approach to getting the context into an EPP template.
Now, if you have two "compatible contexts", you can relax the typing of the parameter, or go full "give me anything and if you don't have the variables I will error" mode.

The 'multi assign from class" works from Puppet 4.5.0. If you are calling from within a user defined resource, there is no way to get to its local variables from the outside, and you have to pass them as arguments (the parameters of a resource can be accessed though).

I hope this adds missing pieces to the puzzle on how it is intended to use the EPP implementation.

Henrik Lindberg (JIRA)

unread,
May 19, 2016, 9:06:03 PM5/19/16
to puppe...@googlegroups.com

Elaborating on some comments received on my earlier post.

Node and Global name space are always available directly (no need to pass those variables) to EPP templates or functions written in the puppet language.

Note that I used an inline template in the example only for the sake of not having to split it up into a separate template file. The exact same template in the example works in a separate template file then just change the call to epp instead of inline_epp.

# foo.pp
class foo($a= 10, $b=20) {
 $var = 100
}
include foo
notice epp('example.epp', {context => Class[foo]})

# example.epp
<% |Type[Class[foo]] $context | -%>
 <% [$a, $b, $var] = $context %>
 $a = <%= $a %>
 $b = <%= $b %>
 $var = <%= $var %>

If you remove the safety net I added - the example looks like this:

# foo.pp
class foo($a= 10, $b=20) {
 $var = 100
}
include foo
notice epp('example.epp', {context => Class[foo]})

# example.epp
 <% [$a, $b, $var] = $context %>
 $a = <%= $a %>
 $b = <%= $b %>
 $var = <%= $var %>

Now you can pass anything as the value of context - it can be a hash with the keys a, b, var, or an array with three values in that order, or a class reference. If given a hash or a class reference, they keys must be present or the 'multi assignment' will fail.

The current erb function api does not allow for additional parameters to be passed - its behavior is to evaluate multiple templates and concatenate the result (IIRC). Changing that would break API, I would otherwise very much like the idea of making both ERB and EPP similar in that respect. It would require two new functions that has a new API (e.g. erb(), and inline_erb()). To be able to use multi-assign in an ERB we would have to come up with a helper function. OTOH, if you are willing to do that refactoring, why not move to EPP directly? (I understand that if you have done lots of advanced ruby in your template you may not want to / or cannot do that, but then that must have been created with someone with quite a bit or both programming expertise and knowledge about puppet).

All the various ways to do interpolation in the various parts of puppet $ % @ # is enough confusing even for users that know them all very well. Plus the the ERB implementation changed from bare-names to @ (for very good reasons though).

Henrik Lindberg (JIRA)

unread,
May 24, 2016, 4:00:04 PM5/24/16
to puppe...@googlegroups.com

I made earlier private messages public as they did not contain anything sensitive.

Henrik Lindberg (JIRA)

unread,
May 24, 2016, 4:03:03 PM5/24/16
to puppe...@googlegroups.com

Ping Jorie Tappa See earlier comments - there is a request to update the documentation for EPP to more clearly show what the best practise is and how it is supposed to be used. See Greg Sarjeant's post just above this for an example of what is wanted.

Sean McDonald (JIRA)

unread,
May 16, 2017, 7:32:03 PM5/16/17
to puppe...@googlegroups.com
Sean McDonald commented on Improvement PUP-6322

ping Jorie Tappa on the above comment.

This message was sent by Atlassian JIRA (v6.4.14#64029-sha1:ae256fe)
Atlassian logo

Sean McDonald (JIRA)

unread,
May 16, 2017, 7:32:04 PM5/16/17
to puppe...@googlegroups.com
Sean McDonald updated an issue
Change By: Sean McDonald
Labels: triaged

Geoff Nichols (JIRA)

unread,
May 25, 2017, 1:15:12 PM5/25/17
to puppe...@googlegroups.com
Geoff Nichols updated an issue
Change By: Geoff Nichols
Team: Agent

Josh Cooper (Jira)

unread,
Jun 11, 2021, 2:17:01 AM6/11/21
to puppe...@googlegroups.com
Josh Cooper commented on Improvement PUP-6322

I believe this is already documented, so I'm going to close it. Please reopen if I've missed something:

https://puppet.com/docs/puppet/7/lang_template_epp.html

Unlike Embedded Ruby (ERB) templates, EPP templates cannot directly access variables in the calling class without namespacing. Fully qualify variables or pass them in as parameters.

This message was sent by Atlassian Jira (v8.13.2#813002-sha1:c495a97)
Atlassian logo
Reply all
Reply to author
Forward
0 new messages