29
Puppet: What _not_ to do? An interactive journey through the ugly side of Puppet

Puppet: What _not_ to do

Embed Size (px)

DESCRIPTION

Walter Heck's presentation on "Puppet: what _not_ to do: An interactive journey through the ugly side of Puppet" at Puppet Camp Ghent 2013.

Citation preview

Page 1: Puppet: What _not_ to do

Puppet: What_not_ to do?An interactive journey through the ugly side

of Puppet

Page 2: Puppet: What _not_ to do

Walter Heck, Founder of OlinData

2,5 years experience with Puppet in 5+different environments

Experienced Puppet Fundamentals trainer

Had my eyes bleed many times with uglyPuppet code

Page 3: Puppet: What _not_ to do

Design mistakesmight not be glaringly obvious or evenwrong at first, but will cause trouble later

Language mistakesPuppet provides functionality thatshouldn't be used, but is there for edge-cases or historical purposes

Page 4: Puppet: What _not_ to do

Wake up...

Quiz time!

Page 5: Puppet: What _not_ to do

== File: modules/ssh/manifests/ssh.pp

class ssh_install { package { 'ssh': ensure => present }}

class ssh_configure { file { '/etc/ssh/sshd_config': ensure => present }}

Page 6: Puppet: What _not_ to do

== File: modules/ssh/manifests/ssh.pp

class ssh($state = ‘present’ { package { 'ssh': ensure => $state }

file { '/etc/ssh/sshd_config': ensure => $state }}

# problem: classnames won't be autoloaded, classnames shouldn't have verbs in them,classes should be combined, don't put multiple classes in a file

Page 7: Puppet: What _not_ to do

==

schedule { 'maint': range => '2 - 4', period => daily, repeat => 1,}

exec { '/usr/bin/apt-get update': schedule => 'maint',}

Page 8: Puppet: What _not_ to do

==

schedule { 'maint': range => '2 - 4', period => daily, repeat => 1,}exec { '/usr/bin/apt-get update': schedule => 'maint',}# problem: schedule doesn't mean something will execute, a common pitfall. If there is no puppet run between these hours, the apt-get exec will not be run

Page 9: Puppet: What _not_ to do

==$myvar = ‘false’

if ($myvar) { notice(‘this is true’)} else { notice(‘This is false’)}

Page 10: Puppet: What _not_ to do

==$myvar = ‘false’

if ($myvar) { notice(‘this is true’)} else { notice(‘This is false’)}#problem: 'false' evaluates totrue

Page 11: Puppet: What _not_ to do

==

exec { '/etc/init.d/apache start': onlyif => ‘ps aux | grep apache | grep -v grep |wc -l’}

Page 12: Puppet: What _not_ to do

==

exec { '/etc/init.d/apache start': onlyif => ‘ps aux | grep apache | grep -v grep |wc -l’}

# problem: this shouldn't be an exec, but aservice

Page 13: Puppet: What _not_ to do

==

package { 'ssh': ensure => present, name => $::operatingsystem ? { 'Ubuntu' => 'openssh-server', default => 'ssh', },}

Page 14: Puppet: What _not_ to do

== $sshpkgname = $::operatingsystem ? { 'Ubuntu' => 'openssh-server', default => undef,}

if ($sshpkgname == undef) { fail(‘unsupported OS’)} else { package { 'ssh': ensure => present, name => $sshpkgname, }}

#problem: they encourage behaviour that is not scalable, using default options toassume things, etc.

Page 15: Puppet: What _not_ to do

==case $::operatingsystem { 'RedHat', 'CentOS': { file { ‘/etc/httpd/http.conf’: ensure => ‘present’, } } default: { file { ‘/etc/apache2/apache2.conf’: ensure => ‘present’, } } }

Page 16: Puppet: What _not_ to do

==case $::operatingsystem { 'RedHat', 'CentOS': { file { ‘/etc/httpd/http.conf’: ensure => ‘present’, } } default: { file { ‘/etc/apache2/apache2.conf’: ensure => ‘present’, } } }#problem: case without default that fails, instead it assumes

Page 17: Puppet: What _not_ to do

==class wordpress {

$wordpress_archive = 'wordpress-3.4.1.zip'

$apache = $::operatingsystem ? { Ubuntu => apache2, CentOS => httpd, Debian => apache2, default => httpd }

$phpmysql = $::operatingsystem ? { Ubuntu => php5-mysql, CentOS => php-mysql, Debian => php5-mysql, default => php-mysql }

$php = $::operatingsystem ? { Ubuntu => libapache2-mod-php5, CentOS => php, Debian => libapache2-mod-php5, default => php }

package { ['unzip',$apache,$php,$phpmysql]: ensure => latest }}

Page 18: Puppet: What _not_ to do

==class wordpress {

$wordpress_archive == 'wordpress-3.4.1.zip'

$apache == $::operatingsystem ? { Ubuntu => apache2, CentOS => httpd, Debian => apache2, defaultdefault => httpd }

$phpmysql == $::operatingsystem ? { Ubuntu => php5-mysql, CentOS => php-mysql, Debian => php5-mysql, defaultdefault => php-mysql }

$php == $::operatingsystem ? { Ubuntu => libapache2-mod-php5, CentOS => php, Debian => libapache2-mod-php5, defaultdefault => php }

packagepackage { ['unzip',$apache,$php,$phpmysql]: ensure => latest }}#wordpress class shouldn't touch apache, should be a different module

Page 19: Puppet: What _not_ to do

== $files = [ '/etc/mysql', '/var/log/mysql','/var/run/mysql' ]

file { $files: ensure => present, user => mysql, group => mysql, mode => 0755,}

Page 20: Puppet: What _not_ to do

== #arrays of resources are not wrong, but dangerous.

file { '/etc/mysql': ensure => present, user => mysql, group => mysql, mode => 0700, <=== careful with this!}

file { '/var/log/mysql': ensure => present, user => mysql, group => mysql, mode => 0755,}

file { '/var/run/mysql': ensure => present, user => mysql, group => mysql, mode => 0755,}

Page 21: Puppet: What _not_ to do

==

if defined(File['/tmp/foo']) { notify('This configuration includes the /tmp/foo file.')} else { file {'/tmp/foo': ensure => present, }}

Page 22: Puppet: What _not_ to do

==class test {

if defined(File['/tmp/foo']) { notice('This configuration includes the /tmp/foo file.') } else { file {'/tmp/foo': ensure => present, group => root } }

if defined(File['/tmp/foo']) { notice('This configuration includes the /tmp/foo file.') } else { file {'/tmp/foo': ensure => present, group => puppet } }}

include test

defined() is (usually) the wrong solution to a resource defined in two locations. It isdangerous, because it only checks if the resource has been defined elsewhere, not withwhat attributes.

Page 23: Puppet: What _not_ to do

==

class apache2 {

file { '/etc/apache2': ensure => directory, require => Service['apache2'] }

file { '/etc/apache2/apache2.conf': ensure => present, require => File['/etc/apache2'], notify => Service['apache2'],}

package { 'apache2': ensure => present, allowcdrom => true, before => File['/etc/apache2/apache2.conf']}

service { 'apache2': ensure => running, subscribe => File['/etc/apache2/apache2.conf']}}

include apache2

Page 24: Puppet: What _not_ to do

==# dependency loop

class apache2 {

file { '/etc/apache2': ensure => directory, require => Service['apache2'] }

file { '/etc/apache2/apache2.conf': ensure => present, require => File['/etc/apache2'], notify => Service['apache2'], # <=== The notify metaparameter implies before.}

package { 'apache2': ensure => present, allowcdrom => true, before => File['/etc/apache2/apache2.conf']}

service { 'apache2': ensure => running, subscribe => File['/etc/apache2/apache2.conf'] # <=== The subscribe metaparameter impliesrequire.

}

Page 25: Puppet: What _not_ to do

class test {

file { '/tmp/somefile.txt': ensure => 'file', mode => 0600, owner => 'root', group => 'root', source => '/etc/puppet/modules/test/somefile.txt' }

}

include test

Page 26: Puppet: What _not_ to do

==

# use puppet:///modules/ instead of the full path on the puppet master

class test {

file { '/tmp/somefile.txt': ensure => 'file', mode => 0600, owner => 'root', group => 'root', source => 'puppet:///modules/test/somefile.txt' }

}

include test

Page 27: Puppet: What _not_ to do

==class test { file {‘/tmp/large/dir/with/many/subdirs/and/many/files’: ensure => present, owner => root, group => root, recurse => true }}

include test

Page 28: Puppet: What _not_ to do

==

# do not use recurse => true on a dir with over 100+ files

class test {

file {‘/tmp/large/dir/with/many/files’: ensure => present, owner => root, group => root, recurse => true }}

include test

# alternative :’(

class test {

exec {'/bin/chown -R root:root /tmp/large/dir/with/many/files': }}

include test

Page 29: Puppet: What _not_ to do

Questions? Feel free to get in touch!

Walter Heck - OlinDataEmail: [email protected]: @walterheck / @olindata

Web: http://olindata.com