whirlwind tour of puppet 4
TRANSCRIPT
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Who am I?
• Puppet user since 0.22.x
• Author Hiera, MCollective, facts.d, etc
• Blog at http://devco.net
• Tweets at @ripienaar
• Volcane on IRC
• Consultant for hire
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Puppet 4?
• Currently 4.5.2 and uses Semver.
• >10 releases and now ready for production
• Massive internal rewrite
• Formal language specification
• Many new and improved features
• New DSL, but backward(ish) compatible
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Language Types
class ntp ( $servers, $config_dir = undef, $ensure = “present” ) { validate_array($servers) validate_absolute_path($config_dir) if !([$ensure in [“present”, “absent”]) { fail(“not a valid value for ensure”) } }
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
class ntp ( Array[String] $servers, Optional[Pattern[/^\//]] $config_dir, Enum[“present”, “absent”] $ensure = “present” ) { # … }
Language Types
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
type Ntp::Server = Pattern[ /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/
]
Language Types
class ntp ( Array[Ntp::Server] $servers, Optional[Pattern[/^\//]] $config_dir, Enum[“present”, “absent”] $ensure = “present” ) { # … }
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$enable_real = $enable ? { Boolean => $enable, String => str2bool($enable), Numeric => num2bool($enable), default => fail('Illegal value for $enable parameter'), } if 5 =~ Integer[1,10] { notice("it's a number between 1 and 10") }
Language Types
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Hash[String, Struct[{ match => Optional[Enum["all", "any"]], rules => Array[ Struct[{ fact => Optional[Data], operator => Enum["==", "=~", ">", " =>", "<", "<=", "has_ip_network"], value => Data, invert => Optional[Boolean] }] ], data => Optional[Hash[Pattern[/\A[a-z0-9_][a-zA-Z0-9_]*\Z/], Data]], classes => Optional[Array[Pattern[/\A([a-z][a-z0-9_]*)?(::[a-z][a-z0-9_]*)*\Z/]]] }] ]
Language Types
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
type Classifier::Classification = Struct[{ match => Optional[Classifier::Matches], rules => Array[Classifier::Rule], data => Optional[Classifier::Data], classes => Optional[Array[Classifier::Classname]] }]
type Classifier::Classifications = Hash[ String, Classifier::Classification ]
Language Types
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$a={"a" => “b"} $b={"c" => “d"}
notice($a+$b)
Native Data Merges
Notice: Scope(Class[main]): {a => b, c => d}
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$a=[1,2,3] $b=[1,4,5,6]
notice(“sum: ${$a+$b}”) notice(“difference: ${$a-$b}”)
Native Data Merges
sum: [1, 2, 3, 1, 4, 5, 6] difference: [2, 3]
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
File { mode => “0600”, owner => “root”, group => “root” }
file{“/some/file”: source => “puppet:///some/file” }
include another_class
Resource Defaults
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
file { default: mode => “0600”, owner => “root”, group => “root”;
“/some/file”: source => “puppet:///some/file”;
“/some/other/file”: source => “puppet:///other/file”; }
include another_class
Resource Defaults
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
[“puppet”, “facter”].each |$file| { file{“/usr/bin/${file}”: ensure => “link”, target => “/opt/puppetlabs/bin/${file}” } }
Iteration
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$domains = [“example.com”, “example.net”]
$data = $domains.map |$domain| { { $domain => { “relay” => “mx.${domain}” } } }
Iteration
{ “example.com” => {“relay” => “mx.example.com”}, “example.net” => {“relay” => “mx.example.net”} }
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
{ "example.net": { "nexthop": "70.x.x.x", "spamdestination": "[email protected]", "spamthreshold": 1500, "enable_antispam": 1 },
“example.com": { "nexthop": "70.x.x.x", "spamdestination": "[email protected]", "spamthreshold": 1500, "enable_antispam": 1 }, }
Iteration
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
each($domain) |$name, $domain| { mail::domain{$name: * => $domain } }
Iteration
Bonus feature: splat operator!
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$defaults = { “spamthreshold” => 1500, “enable_antispam” => 1 }
each($domain) |$name, $domain| { mail::domain{$name: * => $defaults + $domain } }
Iteration
Merging in the defaults and the supplied
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$defaults = { “spamthreshold” => 1500, “enable_antispam” => 1 }
each($domain) |$name, $domain| { mail::domain{ default: * => $defaults;
$name: * => $domain; } }
Iteration
This is create_resources()
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
each($data) |$item| { notice($item) }
.syntax
$data.each |$item| { notice($item) }
Any function, including old ones
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
class myapp { include myapp::install include myapp::config include myapp::service
notify{“done!”: } }
Default Ordering
Recent Puppet 3 set ordering=manifest for same
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
% facter os { architecture => "x86_64", distro => { release => { full => "7.2.1511", major => "7", minor => "2" }, … }, family => "RedHat", hardware => "x86_64", name => “CentOS", … }
Facts Hash
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
class bob { notice($facts[“os”][“distro”][“release”]) }
Facts Hash
Notice I am not using $::facts ?
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
class bob { $facts = “bad things will happen” }
Facts Hash
Error while evaluating a '=' expression, Attempt to assign to a reserved variable name: 'facts'
It’s globally reserved along with a few others
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
:hierarchy: - "%{facts.fqdn}" - "location_%{facts.location}" - "country_%{facts.country}" - common
Facts Hash
Hiera 3 supports nested hashes too
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$ time facter facter 0.05s user 0.04s system 69% cpu 0.126 total
Facter 3
It’s written in C++ but supports old facts
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$ facter os.distro.release.major 7
$ facter networking.interfaces.lo.bindings.0.address 127.0.0.1
Facter 3
The ‘0’ is for digging into arrays
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
$ puppet apply -e ‘$a = 1;$b = 2;notice($a+$b)’
Improved Parser
You can use a “;” to separate statements
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Improved Parser
Functions can go more or less anywhere
notify{hiera(“something”): }
notice("rand: ${fqdn_rand(100)}”)
notice("rand: ${10 + fqdn_rand(100)}")
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Improved Parser
Functions can go more or less anywhere
$pointless = hiera_hash(“things”)
$thing = $pointless[“thing”]
$thing = hiera_hash(“things”)[“thing”]
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Native Functionsfunction classifier::has_interface_detail ( String $match, Enum["address",“network"] $what="address" ) { $interfaces = $facts[“networking”][“interfaces”] $ips = $interfaces.map |$iname, $interface| { ["bindings", "bindings6"].map |$bname| { $interface[$bname].map |$binding| { $binding[$what] } } }.flatten
$match in $ips }
c::has_interface_detail(“127.0.0.1”) c::has_interface_detail(“::1”) c::has_interface_detail(“127.0.0.0”, “network”)
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Native Functionsfunction classifier::fact_fetch ( String $keys ) { $keys.split(/\./).reduce($facts) |$memo, $key| { if $memo !~ Undef {$memo[$key] } } }
classifier::facts_fetch(“os.distro.release.major”)
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Native Functions
function my::create_resource( String $type, Hash[String, Hash] $instances, Hash $defaults = {} ) { $instances.each |$r_name, $r_properties| { Resource[$type] {$r_name: * => $defaults + $r_properties } } }
Thus a native DSL create_resources()
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Data in Modulesclass ntp ( Array[Ntp::Server] $servers, String $config_file ) {
}
# data/os/AIX.yaml ntp::config_file: /etc/ntpd.conf
# data/common.yaml ntp::config_file: /etc/ntp.conf ntp::servers: - 1.pool.ntp.org …
Replaces params.pp pattern
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Lookup Strategiesclass ntp ( Array[Ntp::Server] $servers, String $config_file ) { # … }
# data/common.yaml lookup_options: ntp::servers: merge: strategy: unique
Replaces hiera_array() and hiera_hash()
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
AIO Packages% rpm -qi puppet-agent … augeas 1.4.0 facter 3.1.8 hiera 3.2.0 marionette-collective 2.8.8 openssl 1.0.2h puppet 4.5.2 puppet-ca-bundle 1.0.7 ruby 2.1.9 ruby-augeas 0.5.0 ruby-selinux 2.0.94 ruby-shadow 2.3.3 ruby-stomp 1.3.3 rubygem-deep-merge 1.0.1 rubygem-hocon 0.9.3 rubygem-net-ssh 2.9.2 rubygem-semantic_puppet 0.1.2 …
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
AIO Packages
% ls -l /etc/puppetlabs /opt/puppetlabs /etc/puppetlabs: total 8 drwxr-xr-x. 6 root root 4096 Mar 23 21:51 code drwxr-xr-x. 4 root root 4096 Apr 15 10:25 mcollective drwxr-xr-x. 3 root root 75 Apr 15 10:25 puppet drwxr-xr-x 3 root root 20 Mar 23 21:37 pxp-agent
/opt/puppetlabs: total 0 drwxr-xr-x. 2 root root 54 Apr 15 10:25 bin drwxr-xr-x. 3 root root 20 Mar 23 21:37 facter drwxr-xr-x 3 root root 20 Mar 23 21:37 mcollective drwxr-xr-x. 9 root root 102 Apr 15 10:25 puppet drwxr-xr-x 4 root root 32 Mar 23 21:54 pxp-agent
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Resources• This talk in blog form http://srt.ly/jj
• Iterating in Puppet http://srt.ly/jk
• Data in Modules http://srt.ly/jg
• Lookup Strategies http://srt.ly/jl
• Resource Wrapper Pattern http://srt.ly/jm
• Params.pp in Puppet 4 http://srt.ly/jn
• The Lookup Function http://srt.ly/jo
• Type Aliases http://srt.ly/jp
• A module showing off modern Puppet http://srt.ly/jq
R.I.Pienaar | [email protected] | http://devco.net | @ripienaar
Questions?
twitter: @ripienaaremail: [email protected]: www.devco.net
github: ripienaarfreenode: Volcane
slack: ripienaar
http://devco.net/