Yamata 
no 
Orochi
Puppet 
Language 
4.0 
henrik.lindberg@puppetlabs.com
notice 1 => 1 
notice 1 + 2 => syntax error 
notice(1 + 2) => 3 
notice 1,2,3 => 1 2 3 
notice [1,2,3] => 1 2 3 
notice [1,2],3 => 1 2 3 
notice 5 in [5] => true 
notice (4+1) in [5] => error, not a string 
notice 5 in [4+1] => false 
notice 5.0 in [5] => false 
notice(0xff =~ /5/) => false 
notice((0xfe+1) =~/5/) => true 
notice { a=>10 } => error, no title
Puppet 
4.0 
• Language 
Cleanup 
– Sanity, 
Principle 
of 
Least 
Surprise 
– Expressions, 
Expressions, 
Expressions 
• Features 
– Misc 
enhancements 
– Resource 
Expression 
Features 
– IteraGon 
– Type 
System 
/ 
OpGonal 
Typing 
– Embedded 
Puppet 
Templates 
(EPP) 
– Heredoc
Cleanup 
• Language 
SpecificaGon 
– 
yes 
we 
have 
one 
– hQps://github.com/puppetlabs/puppet-­‐specificaGons 
• Numbers 
are 
Numbers 
• No 
magic 
to-­‐string 
for 
=~ !~ in 
• Upper 
case 
bare 
words 
are 
Type 
References 
• Empty 
string 
is 
not 
undef 
(and 
thus 
"thruty") 
• InterpolaGon 
follows 
specified 
rules 
• +=, 
[]= 
removed, 
no 
more 
mutaGon
Misc 
new 
features 
1(7) 
• Concatenate 
Arrays 
with 
+ 
[1,2,3] + [4,5,6] => [1,2,3,4,5,6] 
• Merge 
Hashes 
with 
+ 
{a=>1} + {b=>2} => {a=>1, b=>2} 
• Delete 
with 
-­‐ 
[1,2,3] – [2, 3] => [1] 
{a=>1, b=>2, c=>3} – [a,c] => {b=>2}
Misc 
new 
features 
2(7) 
• Append 
to 
Array 
with 
<< 
[1,2,3] << 4 => [1,2,3,4] 
[1,2,3] << [4,5,6] => [1,2,3,[4,5,6]]
Misc 
new 
features 
3(7) 
• Unfold 
with 
unary 
* 
$a = [2,3] 
$b = [1, *$a, 4] => [1,2,3,4] 
• Unfold 
in 
case 
opGon, 
selector 
and 
call 
$a = [1,2,3] 
case 1 { 
*$a : { # 1 or 2 or 3 
} 
} 
notice *$a => 1,2,3 
notice $a => [1,2,3]
Misc 
new 
features 
4(7) 
• Substring 
in 
string 
'cd' in "abcde" => true 
• Substring 
with 
[] 
"xyzabcdef"[3,3] => "abc" 
"xyzabcdef"[3] => "a" 
"xyzabcdef"[3,-2] => "abcde"
Misc 
new 
features 
5(7) 
• Matches 
with 
Regexp 
in 
String 
form 
$a = "example.com" 
$url =~ "http://$a.*"
Misc 
new 
features 
6(7) 
• Detailed 
Error 
Messages 
– SemanGc 
validaGon 
unless 
lex 
or 
syntax 
errors 
– Outputs 
posiGon 
on 
line 
– Can 
report 
more 
than 
one 
error
Expression 
Based 
Grammar 
6(7) 
• if, 
unless, 
case 
are 
expressions 
notice if 1 > 2 { true } else { false } 
# => false 
$a = 
case 2 { 
1, 2, 3: { yes } 
default: { no } 
} 
# => $a == yes
Resource 
Expression
Local 
Defaults 
file { 
default: 
mode => '444', 
owner => 'admin'; 
title: 
. . . ; 
}
Unfold 
Hash 
file { 
default: 
* => $defaults_hash; 
'tmp/foo': 
mode => '666', 
* => $params_hash; 
}
Create 
Resources 
Equiv. 
in 
Puppet 
Resource[$type] { 
default: 
* => $defaults_hash; 
$titles: 
* => $params_hash; 
}
LOOOOOOOPS 
• Iterate 
over: 
– Arrays 
– Hashes 
– Strings 
– Integer 
ranges 
• Implemented 
as 
funcGons 
taking 
callable 
code 
blocks 
(lambdas) 
= 
open 
design 
• Calls 
can 
now 
be 
expressed 
from 
leh 
to 
right 
using 
'.' 
notaGon
each 
• Do 
something 
with 
each 
element 
• Returns 
LHS 
[1,2,3].each |$x| { notice $x } 
each([1,2,3]) |$x| { notice $x }
map 
• Transform 
each 
element 
• Returns 
transformed 
result 
[1,2,3].map |$x| { $x*10 } 
=> [10,20,30]
filter 
• Produces 
elements 
that 
match 
• Returns 
filtered 
result 
[1,2,3].filter|$x| { $x >= 2 } 
=> [2,3]
reduce 
• Transforms 
/ 
reduces 
many 
to 
one 
• Feeds 
seed/previous 
result 
into 
next 
iteraGon 
• Returns 
transformed 
result 
[1,2,3].reduce |$result, $x| { 
$result + $x 
} 
=> 6
And 
more
E-­‐I-­‐E-­‐I-­‐O
E-­‐I-­‐E-­‐I-­‐O
E-­‐I-­‐E-­‐I-­‐O
E-­‐I-­‐E-­‐I-­‐O
The 
Puppet 
Type 
System 
Cow 
Integer
Puppet 
Types 
• Puppet 
Types 
are 
first 
order 
objects 
(they 
can 
be 
assigned 
and 
passed 
around 
in 
variables) 
• Uses 
syntax 
familiar 
from 
Resource 
– 
i.e. 
Class, 
File, 
User, 
where 
[ 
] 
applied 
to 
the 
type 
makes 
it 
more 
specific 
– 
e.g. 
File['foo']
Example 
Integer 
# All integers 
Integer 
# All integers >=42 
Integer[42] 
# All integers >=42 and <=142 
Integer[42,142]
AutomaGc 
type 
checking! 
define mytype(Integer[80,443] $port){ 
# port guaranteed to be integer 
# and between 80 and 443 
# otherwise an error 
}
More 
advanced 
type 
checking! 
define mytype($port) { 
assert_type(Integer[80,443], $port) |$expected, $got| { 
warn("Bad port $got, expected $expected. Using port 80.") 
80 
} 
} 
• 
Code 
block 
called 
if 
given 
does 
not 
match 
• 
…do 
what 
you 
want, 
fail, 
warn, 
return 
default
OperaGons 
on 
Type 
• Since 
a 
Type 
is 
a 
kind 
of 
PaQern… 
– Match 
with 
=~ 
and 
!~ 
– Match 
in 
case 
expression 
• Since 
Types 
are 
defined 
in 
a 
hierarchy: 
– Compare 
types 
with 
<, 
<=, 
>, 
>= 
# is $x an integer ? 
$x =~ Integer 
# is $t more specific than Integer 
$t = Integer[80, 144] 
$t < Integer
Type 
Hierarchy 
Any 
|- Scalar 
| |- Numeric 
| | |- Integer[from, to] 
| | |- Float[from, to] 
| | 
| |- String[from, to] 
| | |- Enum[*strings] 
| | |- Pattern[*patterns] 
| | 
| |- Boolean 
| |- Regexp[pattern_string]
Type 
Hierarchy 
Any 
|- Collection 
| |- Array[T] 
| | |- Tuple[T*, from, to] 
| | 
| |- Hash[K, V] 
| | |- Struct[{ key => T, ...}] 
| 
|- Variant[T*] 
|- Optional[T] 
| 
|- Undef 
|- Default 
| 
|- Type[T]
Type 
Hierarchy 
Any 
|- CatalogEntry 
| |- Resource[type_name, title] 
| |- Class[class_name] 
| 
|- Undef 
|- Data 
| |- Scalar 
| |- Array[Data] 
| |- Hash[Scalar, Data] 
| |- Undef
EPP
EPP 
– 
Templates 
in 
Puppet 
• Same 
template 
markup 
as 
ERB 
– Logic 
is 
Puppet 
instead 
of 
Ruby 
AND 
• Can 
be 
parameterized 
! 
• Use 
funcGons 
epp(template) 
inline_epp(string) 
• instead 
of 
template() 
inline_template()
Example 
EPP 
$x = 'human' 
inline_epp('This is not the <%= $x %> you are looking 
for.') 
# => 'This is not the human you are looking for.' 
$x = 'human' 
inline_epp('This is not the <%= $x %> you are looking 
for.', { 'x' => 'droid'}) 
# => 'This is not the droid you are looking for.' 
<%- |$x = 'human'| -%> 
This is not the <%= $x %> you are looking for.
Heredoc
Puppet 
Heredoc 
• For 
more 
detailed 
control 
over 
a 
block 
of 
text 
• No, 
or 
selected 
set 
of 
escapes 
• InterpolaGon 
or 
no 
interpolaGon 
• Can 
be 
syntax 
checked 
by 
parser 
(JSon 
in 
core, 
can 
add 
plugin 
language 
support) 
• Control 
over 
leh 
margin
Heredoc 
-­‐ 
Syntax 
ENDS-­‐HERE 
anything 
not 
in 
<text> 
"ENDS-­‐HERE" 
with 
interpola:on 
:json 
syntax 
check 
result 
/tsrn$L 
turns 
on 
escape 
/ 
turns 
on 
all 
@( ["]<endtag>["] [:<syntax>] [/<escapes>] ) 
<text> 
[|][-] <endtag> 
| 
set 
le= 
margin 
-­‐ 
trim 
trailing 
t 
tab 
s 
space 
r 
return 
n 
new-­‐line 
$ 
$ 
L 
<end 
of 
line>
Puppet 
Heredoc 
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 
#.........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
Ruby 
API
Ruby 
API 
• 4x 
FuncGon 
API 
– type 
checked 
– dispatch 
to 
impl 
based 
on 
given 
types 
– more 
powerful 
– safer 
• Binder 
– composable 
type 
safe 
injecGon 
– for 
plugins 
and 
data 
(e.g. 
syntax 
checkers)
Summary 
• Language 
Cleanup 
• More 
strict 
• New 
Features 
• BeQer 
Error 
Messages 
• IteraGon 
• Type 
System 
• Puppet 
Templates 
– 
EPP 
• Heredoc
In 
pracGce 
• Run 
now 
with 
–parser 
future 
• Fix 
deprecaGons 
and 
issues 
• Make 
backwards 
compaGble 
changes 
and 
conGnue 
in 
producGon 
on 
3x 
• Test 
carefully 
and 
conGnue 
running 
on 
what 
will 
be 
Puppet 
4.0 
• 4.0 
expected 
release 
before 
end 
of 
the 
year
Links 
• github/puppetlabs/puppet-­‐specificaGons 
• hQp://puppet-­‐on-­‐the-­‐edge.blogspot.com/ 
• TwiQer 
@hel 
• IRC 
helindbe

Puppet Language 4.0 - PuppetConf 2014

  • 2.
  • 6.
    Puppet Language 4.0 henrik.lindberg@puppetlabs.com
  • 11.
    notice 1 =>1 notice 1 + 2 => syntax error notice(1 + 2) => 3 notice 1,2,3 => 1 2 3 notice [1,2,3] => 1 2 3 notice [1,2],3 => 1 2 3 notice 5 in [5] => true notice (4+1) in [5] => error, not a string notice 5 in [4+1] => false notice 5.0 in [5] => false notice(0xff =~ /5/) => false notice((0xfe+1) =~/5/) => true notice { a=>10 } => error, no title
  • 13.
    Puppet 4.0 •Language Cleanup – Sanity, Principle of Least Surprise – Expressions, Expressions, Expressions • Features – Misc enhancements – Resource Expression Features – IteraGon – Type System / OpGonal Typing – Embedded Puppet Templates (EPP) – Heredoc
  • 14.
    Cleanup • Language SpecificaGon – yes we have one – hQps://github.com/puppetlabs/puppet-­‐specificaGons • Numbers are Numbers • No magic to-­‐string for =~ !~ in • Upper case bare words are Type References • Empty string is not undef (and thus "thruty") • InterpolaGon follows specified rules • +=, []= removed, no more mutaGon
  • 16.
    Misc new features 1(7) • Concatenate Arrays with + [1,2,3] + [4,5,6] => [1,2,3,4,5,6] • Merge Hashes with + {a=>1} + {b=>2} => {a=>1, b=>2} • Delete with -­‐ [1,2,3] – [2, 3] => [1] {a=>1, b=>2, c=>3} – [a,c] => {b=>2}
  • 17.
    Misc new features 2(7) • Append to Array with << [1,2,3] << 4 => [1,2,3,4] [1,2,3] << [4,5,6] => [1,2,3,[4,5,6]]
  • 18.
    Misc new features 3(7) • Unfold with unary * $a = [2,3] $b = [1, *$a, 4] => [1,2,3,4] • Unfold in case opGon, selector and call $a = [1,2,3] case 1 { *$a : { # 1 or 2 or 3 } } notice *$a => 1,2,3 notice $a => [1,2,3]
  • 19.
    Misc new features 4(7) • Substring in string 'cd' in "abcde" => true • Substring with [] "xyzabcdef"[3,3] => "abc" "xyzabcdef"[3] => "a" "xyzabcdef"[3,-2] => "abcde"
  • 20.
    Misc new features 5(7) • Matches with Regexp in String form $a = "example.com" $url =~ "http://$a.*"
  • 21.
    Misc new features 6(7) • Detailed Error Messages – SemanGc validaGon unless lex or syntax errors – Outputs posiGon on line – Can report more than one error
  • 22.
    Expression Based Grammar 6(7) • if, unless, case are expressions notice if 1 > 2 { true } else { false } # => false $a = case 2 { 1, 2, 3: { yes } default: { no } } # => $a == yes
  • 23.
  • 24.
    Local Defaults file{ default: mode => '444', owner => 'admin'; title: . . . ; }
  • 25.
    Unfold Hash file{ default: * => $defaults_hash; 'tmp/foo': mode => '666', * => $params_hash; }
  • 26.
    Create Resources Equiv. in Puppet Resource[$type] { default: * => $defaults_hash; $titles: * => $params_hash; }
  • 28.
    LOOOOOOOPS • Iterate over: – Arrays – Hashes – Strings – Integer ranges • Implemented as funcGons taking callable code blocks (lambdas) = open design • Calls can now be expressed from leh to right using '.' notaGon
  • 29.
    each • Do something with each element • Returns LHS [1,2,3].each |$x| { notice $x } each([1,2,3]) |$x| { notice $x }
  • 30.
    map • Transform each element • Returns transformed result [1,2,3].map |$x| { $x*10 } => [10,20,30]
  • 31.
    filter • Produces elements that match • Returns filtered result [1,2,3].filter|$x| { $x >= 2 } => [2,3]
  • 32.
    reduce • Transforms / reduces many to one • Feeds seed/previous result into next iteraGon • Returns transformed result [1,2,3].reduce |$result, $x| { $result + $x } => 6
  • 33.
  • 37.
  • 39.
  • 41.
  • 44.
  • 46.
    The Puppet Type System Cow Integer
  • 47.
    Puppet Types •Puppet Types are first order objects (they can be assigned and passed around in variables) • Uses syntax familiar from Resource – i.e. Class, File, User, where [ ] applied to the type makes it more specific – e.g. File['foo']
  • 48.
    Example Integer #All integers Integer # All integers >=42 Integer[42] # All integers >=42 and <=142 Integer[42,142]
  • 49.
    AutomaGc type checking! define mytype(Integer[80,443] $port){ # port guaranteed to be integer # and between 80 and 443 # otherwise an error }
  • 50.
    More advanced type checking! define mytype($port) { assert_type(Integer[80,443], $port) |$expected, $got| { warn("Bad port $got, expected $expected. Using port 80.") 80 } } • Code block called if given does not match • …do what you want, fail, warn, return default
  • 51.
    OperaGons on Type • Since a Type is a kind of PaQern… – Match with =~ and !~ – Match in case expression • Since Types are defined in a hierarchy: – Compare types with <, <=, >, >= # is $x an integer ? $x =~ Integer # is $t more specific than Integer $t = Integer[80, 144] $t < Integer
  • 52.
    Type Hierarchy Any |- Scalar | |- Numeric | | |- Integer[from, to] | | |- Float[from, to] | | | |- String[from, to] | | |- Enum[*strings] | | |- Pattern[*patterns] | | | |- Boolean | |- Regexp[pattern_string]
  • 53.
    Type Hierarchy Any |- Collection | |- Array[T] | | |- Tuple[T*, from, to] | | | |- Hash[K, V] | | |- Struct[{ key => T, ...}] | |- Variant[T*] |- Optional[T] | |- Undef |- Default | |- Type[T]
  • 54.
    Type Hierarchy Any |- CatalogEntry | |- Resource[type_name, title] | |- Class[class_name] | |- Undef |- Data | |- Scalar | |- Array[Data] | |- Hash[Scalar, Data] | |- Undef
  • 55.
  • 56.
    EPP – Templates in Puppet • Same template markup as ERB – Logic is Puppet instead of Ruby AND • Can be parameterized ! • Use funcGons epp(template) inline_epp(string) • instead of template() inline_template()
  • 57.
    Example EPP $x= 'human' inline_epp('This is not the <%= $x %> you are looking for.') # => 'This is not the human you are looking for.' $x = 'human' inline_epp('This is not the <%= $x %> you are looking for.', { 'x' => 'droid'}) # => 'This is not the droid you are looking for.' <%- |$x = 'human'| -%> This is not the <%= $x %> you are looking for.
  • 58.
  • 59.
    Puppet Heredoc •For more detailed control over a block of text • No, or selected set of escapes • InterpolaGon or no interpolaGon • Can be syntax checked by parser (JSon in core, can add plugin language support) • Control over leh margin
  • 60.
    Heredoc -­‐ Syntax ENDS-­‐HERE anything not in <text> "ENDS-­‐HERE" with interpola:on :json syntax check result /tsrn$L turns on escape / turns on all @( ["]<endtag>["] [:<syntax>] [/<escapes>] ) <text> [|][-] <endtag> | set le= margin -­‐ trim trailing t tab s space r return n new-­‐line $ $ L <end of line>
  • 61.
    Puppet Heredoc 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 #.........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
  • 62.
  • 63.
    Ruby API •4x FuncGon API – type checked – dispatch to impl based on given types – more powerful – safer • Binder – composable type safe injecGon – for plugins and data (e.g. syntax checkers)
  • 64.
    Summary • Language Cleanup • More strict • New Features • BeQer Error Messages • IteraGon • Type System • Puppet Templates – EPP • Heredoc
  • 65.
    In pracGce •Run now with –parser future • Fix deprecaGons and issues • Make backwards compaGble changes and conGnue in producGon on 3x • Test carefully and conGnue running on what will be Puppet 4.0 • 4.0 expected release before end of the year
  • 67.
    Links • github/puppetlabs/puppet-­‐specificaGons • hQp://puppet-­‐on-­‐the-­‐edge.blogspot.com/ • TwiQer @hel • IRC helindbe