Replacing "exec" with a type and provider


Published on

Far too often we abuse the "exec" type, when what we really need is a simple provider that allows for more complex tests and exception handling. This talk will show how to change that enormous "exec" resource to a new type and provider, then return your manifests to a declarative config description.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Replacing "exec" with a type and provider

  1. 1. Replacing "exec" with a type and provider Return manifests to a declarative configuration Dominic Cleal <>
  2. 2. Puppets declarative DSLuser { dcleal: ensure => present, comment => Dominic Cleal, shell => /bin/bash,}package { vim: ensure => present,}
  3. 3. How execs can fail$ puppet module install puppetlabs-apt$ vim apt/manifests/key.pp...exec { "apt::key ${upkey} absent": command => "apt-key del ${upkey}", path => /bin:/usr/bin, onlyif => "apt-key list | grep ${upkey}", user => root, group => root, logoutput => on_failure,}
  4. 4. Convert the exec to a type/provider user typeensurenamecomment useraddshellhome provider exists?, create, destroy comment, comment= useradd <user> shell, shell= home, home= usermod <user> userdel <user>
  5. 5. Types: properties and parameters● Properties are changeable, e.g. a users shell or a services start-at-boot flag● Parameters represent other required data, e. g. hasrestart on service● All data can be validated and munged● Types can be "ensurable", if the object can: ○ exist and not exist ○ be created ○ be destroyed
  6. 6. Convert the exec to a type/provider apt_key typeensurekey keyring providerkey_server exists? create apt-key list destroy apt-key --recv-keys.. apt-key del
  7. 7. Types: simple example$ cat apt_key/lib/puppet/type/apt_key.rbPuppet::Type.newtype(:apt_key) do @doc = "Manages apt keys" ensurable newparam(:key) do desc "The key ID" isnamevar end newparam(:key_server) do desc "Key server to download key form" defaultto "" endend
  8. 8. Types: known valuesPuppet::Type.type(:file).newparam(:checksum) do desc "The checksum type to use whendetermining whether to replace a files contents. The default checksum type is md5." newvalues "md5", "md5lite", "mtime", "ctime","none" defaultto :md5end
  9. 9. Types: validationmodule Puppet newtype(:schedule) do newparam(:repeat) do desc "How often a given resource may be appliedin this schedules `period`. Defaults to 1; must be aninteger." validate do |value| unless value.is_a?(Integer) or value =~/^d+$/ raise Puppet::Error, "Repeat must be a number" end end
  10. 10. Providers: getters/setters, ensurable● getters and setters are implemented for each property● ensurable types also have exists?, create and destroy to manage its existence● list of commands that are required to run● confined to certain operating systems via facts
  11. 11. Providers: simple example$ cat apt_key/lib/puppet/provider/apt_key/keyring.rbPuppet::Type.type(:apt_key).provide(:keyring) do commands :aptkey => "/usr/bin/apt-key" def exists? aptkey("list").include? resource[:key].upcase end def create aptkey "adv", "--keyserver", resource[:key_server], "--recv-keys", resource[:key].upcase end def destroy aptkey "del", resource[:key].upcase endend
  12. 12. Providers: confinementPuppet::Type.type(:group).provide :aix do desc "Group management for AIX." confine :operatingsystem => :aix defaultfor :operatingsystem => :aixPuppet::Type.type(:exec).provide :posix do confine :feature => :posix defaultfor :feature => :posix
  13. 13. Providers: instances and ralsh$ puppet resource hosthost { argon: ensure => present, host_aliases => [foo], ip =>, target => /etc/hosts,}host { iridium: ensure => present, host_aliases => [localhost.localdomain, localhost], ip =>, target => /etc/hosts,}
  14. 14. Providers: instances and ralshdef self.instances resources = [] aptkey("list").each_line { |k| resources << new({:name => $1}) if k =~ /^pubs+w+/(w+)/ } resourcesend# puppet resource apt_keyapt_key { 1F41B907: ensure => present}apt_key { 46925553: ensure => present
  15. 15. Testing providers with rspecprov_c = Puppet::Type.type(:apt_key).provider(:keyring)describe prov_c do it "should remove key" do resource = Puppet::Type.type(:apt_key).new( :name => 16BA136C, :ensure => :absent ) provider = provider.expects(:aptkey).with(del, 16BA136C) provider.destroy endend
  16. 16. Creating a module$ puppet module generate domcleal-apt_key$ cd domcleal-apt_key$ mkdir -p lib/puppet/type lib/puppet/provider/apt_key$ touch lib/puppet/type/apt_key.rb lib/puppet/provider/apy_key/keyring.rb$ puppet module build .upload pkg/domcleal-apt_key-0.0.1.tar.gz
  17. 17. Resources● guides ○ Writing custom types & providers ○ Provider development● Puppet Types and Providers ○ Dan Bode & Nan Liu, OReilly, 2012● puppet source itself, spec/unit/provider/● puppetlabs_spec_helper