Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Absolute Beginners Guide to Puppet Through Types

Eeafaae6e61a7193e0134e3b39c3ba34?s=47 Igor Galić
September 23, 2014

Absolute Beginners Guide to Puppet Through Types

When we teach people Puppet, we usually start from the DSL: Here's how you can create a file. This is how you add a user. You can install all kinds of packages. Then as soon as they discover `exec`, it all goes downhill for those who think it's just like bash!

Puppet's true power lies in its types. Rather than trying to shield beginners from those, we want to expose them to types as early as possible.

In this [failed] experiment, I want to do exactly that. I invite complete beginners to join us and learn more about Puppet's internals. Once we're able to answer the "why", the "how" will come naturally!



Igor Galić

September 23, 2014


  1. Complete Beginners' Guide to Puppet - Through Types!

  2. Guide to Puppet - Through Types!

  3. whoami Igor Galić igalic (gh/irc) @hirojin (twitter)

  4. whoami

  5. how i got here ✈

  6. how i got here c ... bash ... perl linux

    ... make ... ansible puppet
  7. how i got here

  8. why this talk exists

  9. why this talk exists

  10. dijkstra "The art of programming is the art of organizing

    complexity, of mastering multitude and avoiding its bastard chaos as effectively as possible."
  11. dijkstra "Simplicity is a great virtue but it requires hard

    work to achieve it and education to appreciate it. And to make matters worse: complexity sells better."
  12. nooop include 'ssh'

  13. hiera class { 'ssh': permit_root_login => false, }

  14. include include 'ssh'

  15. resources igalic@levix ~ % puppet resource user igalic user {

    'igalic': ensure => 'present', comment => 'Igor Galić,,,', gid => '1000', groups => ['adm', 'cdrom', 'sudo', 'dip', 'plugdev', 'lpadmin', 'sambashare', ' home => '/home/igalic', shell => '/bin/zsh', uid => '1000', } igalic@levix ~ %
  16. differences dsl detail types & providers nope access to the

    RAL yupp sub-types branching impl diff platforms providers same/same contract/impl type/provider "easy" overload $name messy
  17. defined type define trafficserver::config::records ( $changes = [ $title ],

    ) { include 'trafficserver' $configfile = "${::trafficserver::sysconfdir}/records.config" $lens = 'Trafficserver_records.lns' $context = "/files${configfile}" $incl = $configfile augeas { "${lens}_${title}": lens => $lens, context => $context, incl => $incl, changes => $changes, notify => Exec[trafficserver-config-reload], } }
  18. symmetry @@trafficserver_record { 'proxy.config.http.server_ports': changes => '80:ipv4 80:ipv6', }

  19. "simple" type Puppet::Type.newtype(:trafficserver_record) do desc 'trafficserver_record is a type to

    manage records.config entries' newparam(:record, :namevar => true) do desc "record entry" end newproperty(:value) do desc "Value of this record" end end
  20. intermezzo

  21. "simple" provider Puppet::Type.type(:trafficserver_record).provide(:traffic_line) do desc 'Manage traffic server records.config entries

    using traffic_line command' commands :traffic_line => 'traffic_line' mk_resource_methods ConfigPattern = 'proxy.(config|local|cluster).*' def initialize(value={}) super(value) end def name=(value) @property_hash[:name] = value end # this method is only called when value isn't insync? def value=(value) @property_hash[:name] = resource[:name]
  22. intermezzo

  23. defined type define git::config( $value, $section = regsubst($name, '^([^\.]+)\.([^\.]+)$','\1'), $key

    = regsubst($name, '^([^\.]+)\.([^\.]+)$','\2'), $user = 'root', ) { exec{"git config --global ${section}.${key} '${value}'": environment => inline_template('<%= "HOME=" + ENV["HOME"] %>'), path => ['/usr/bin', '/bin', '/usr/local/bin'], user => $user, unless => "git config --global --get ${section}.${key} '${value}'", } }
  24. implementation (wrong) exec{"git config --global ${section}.${key} '${value}'": environment => inline_template('<%=

    "HOME=" + ENV["HOME"] %>'), path => ['/usr/bin', '/bin', '/usr/local/bin'], user => $user, unless => "git config --global --get ${section}.${key} '${value}'", }
  25. type Puppet::Type.newtype(:git_config) do validate do fail('it is required to pass

    "value"') if self[:value].nil? || self[:value].em end newparam(:name) do desc "The default namevar" end newparam(:user) do desc "The user for which the config will be set. Default value: root" defaultto "root" end newparam(:section, :namevar => true) do desc "The configuration section. Example: user." end newparam(:key, :namevar => true) do desc "The configuration key. Example: email." end
  26. implementation (correct) Puppet::Type.type(:git_config).provide(:git_config) do mk_resource_methods def check_current?(value) require 'etc' user

    = @resource[:user] key = @resource[:key] section = @resource[:section] home = Etc.getpwnam(user)[:dir] current = Puppet::Util::Execution.execute( "git config --global --get #{section}.#{key}", :uid => user, :failonfail => false, :custom_environment => { 'HOME' => home } ) return value == current.strip end def update
  27. done

  28. references puppet types and providers by Dan Bode & Nan

    Liu shit gary larizza says, e.g.: http://garylarizza.com/blog/2013 /12/15/seriously-what-is-this-provider-doing/ <3 ADRIEN THEBO <3 Morgan Haskel <3 Ashley Penney </3 Hunter Haugen <3 pry <3 https://github.com/Brainsware/puppet-trafficserver https://github.com/puppetlabs/puppetlabs-git