"Loops and Unicorns - The Future of the Puppet Language" by Henrik Lindberg, Platform Engineer, Puppet Labs.
Presentation Overview: Loops, Unicorns and other magical animals lives in your puppet since Puppet 3.2. This is the first version to ship with the future just a setting away! In this talk you will see the new features at work; we are talking loops, lambdas, puppet templates and other unicorns! In addition to learning how loops work, we will present the background to the new parser and the future capabilities this enables such as being able to support multiple language compliance levels, provide better error messages, and much more. Parts of this talk will touch on advanced topics such has to use lambdas in your custom functions.
Speaker Bio: Henrik has 30 years of experience architecting and developing software. Past positions include CTO of Cloudsmith Inc, leadership of BEA’s Java Run-Time Group (JRockit) and CTO and/or technical founder of several publicly and privately held software companies. Henrik works on the Platform team at Puppet Labs with special focus on the Puppet Language. He is also a committer and leader of several Eclipse projects, and leads the Puppet IDE Geppetto project.
2. Loops and Unicorns
Future of the Puppet Language
Henrik Lindberg
Consulting Engineer | Puppet Labs
@hel
3. puppetconf.com #puppetconf
• New parser
• New Language Features
• New approach
– Opt in to New/Experimental Features
– Maintaining Backwards Compatibility
Introduction
5. puppetconf.com #puppetconf
• Rewritten from the ground up
• Removes quirky grammar constraints
• Improves error messages
• Enabler for:
– opt-in to new and experimental features
– backwards compatibility
• Use on command line, or in settings
New Parser
puppet apply –-parser future ...
6. puppetconf.com #puppetconf
De-Quirk
"This is a random number: ${fqdn_rand()}"
join([1,2,3])
$a = 0x0EH
$b = 0778
Interpolation and functions work:
Literal Array / Hash as argument in calls works:
Numbers must now be valid:
9. puppetconf.com #puppetconf
Error Reporting
Error: Could not parse for environment production:
Syntax error at 'node' at line 1 on node
kermit.example.com
puppet apply -e '$a = node "a+b" { }'
Then:
Now: Error: Invalid use of expression. A Node Definition
does not produce a value at line 1:6
Error: The hostname 'a+b' contains illegal characters
(only letters, digits, '_', '-', and '.' are allowed)
at line 1:11
Error: Classes, definitions, and nodes may only appear
at toplevel or inside other classes at line 1:6
Error: Could not parse for environment production:
Found 3 errors. Giving up on node kermit.example.com
11. puppetconf.com #puppetconf
• Forgiving Grammar
• Validation is separate
– Can validate a particular language version
– Language version != Puppet version
• Evaluation is separate
– Can evaluate a particular language version way
– Language version != Puppet version
Separation of Language
Concerns
26. puppetconf.com #puppetconf
Collect
$a = [1, 2, 3]
notice $a.collect |$value| { $v * 10 }
Transform each element with collect:
Produces:
Notice: Scope(Class[main]): 10 20 30
27. puppetconf.com #puppetconf
Reduce
$a = [1, 2, 3]
notice $a.reduce |$memo, $value| { $memo + $value }
Reduce all elements into one:
Produces:
Notice: Scope(Class[main]): 6
28. puppetconf.com #puppetconf
Examples
$usernames.each |$x| {
file { "/home/$x/.somerc":
owner => $x
}
}
Set ownership of some "rc-file" for each user:
Setting 'owner' and 'mode' from a Hash:
$users_with_mode = ['fred' => 0666, 'mary' => 0777 ]
$users_with_mode.each |$user, $mode| {
file {"/home/$user/.somerc":
owner => $user,
mode => $mode
}
}
29. puppetconf.com #puppetconf
Examples
$a.select |$x| { $x =~ /com$/ }.each |$x| {
file { "/somewhere/$x":
owner => $x
}
}
Filter and create resources:
Include classes based on array of roles:
$roles.each |$x| { include "role_$x" }
30. puppetconf.com #puppetconf
Custom Function (Ruby)
pp_block = args[-1]
Lambda always last argument:
Was it given?
Call it:
pp_block.is_a? Puppet::Parser::AST::Lambda
# in a custom function, self is scope)
pp_block.call(self, 'hello', 'world')
32. Heredoc
Not yet on master branch
https://github.com/puppetlabs/puppet/pull/1659
33. puppetconf.com #puppetconf
Heredoc - Syntax
@( ["]<endtag>["] [:<syntax>] [/<escapes>] )
<text>
[|][-] <endtag>
ENDS-‐HERE
anything
not
in
<text>
"ENDS-‐HERE"
with
interpola2on
:json
syntax
check
result
/tsrn$L
turns
on
escape
/
turns
on
all
|
set
le7
margin
-‐
trim
trailing
t
tab
s
space
r
return
n
new-‐line
$
$
L
<end
of
line>
34. puppetconf.com #puppetconf
Heredoc – example
Example:
#.........1.........2.........3.........4.........5....
$a = @(END)
This is indented 2 spaces in the source, but produces
a result flush left with the initial 'T'
This line is thus indented 2 spaces.
| END
35. puppetconf.com #puppetconf
Heredoc – example
multiple on same line:
#.........1.........2.........3.........4.........5....
foo(@(FIRST), @(SECOND))
This is the text for the first heredoc
FIRST
This is the text for the second
SECOND
39. puppetconf.com #puppetconf
Use by calling
epptemplate(<name> [,<params_hash>])
inline_epptemplate(<text>[,<params_hash>])
Puppet Templates
$x = 'human'
inline_epptemplate('This is not the <%= $x %> you are
looking for.', { 'x' => 'droid'})
# => 'This is not the droid you are looking for.'
40. puppetconf.com #puppetconf
• Parameterized
– declare parameters
– set default values
– parameter without value and no default = error
Puppet Templates
<%- ($x = 'human') -%>
This is not the <%= $x %> you are looking for.
43. puppetconf.com #puppetconf
• More powerful data bindings
• For both Data, and Puppet Extensions
• Composes Hiera2 data in modules and
environment + Hiera1
• Bindings in Ruby
• Opt in on command line or in settings
Puppet Binder
puppet apply --binder
puppet apply –-parser future ...
44. puppetconf.com #puppetconf
• Default:
– All hiera-2 data (in default location) and all
(default) ruby bindings from all modules on
module path composed
– Site level hiera-2 data and ruby bindings
override contributions from modules.
• Customize
– include alternatives, exclude bindings
– add / reorganize overriding "layers"
Configuration