Friday, February 1, 13
I am:
I work for:
I help:
Daniele Sluijters (daenney)
Nedap Stepping Stone
Developers host and scale their applications
Friday, February 1, 13
Friday, February 1, 13
Friday, February 1, 13
Friday, February 1, 13
• Catering for everyone’s needs
• From a single codebase...
Departments
Friday, February 1, 13
So, Puppet...
Friday, February 1, 13
• Started to backsource our hosting.
• Need for automation to grow quickly.
• Single point of administration.
• Servers bootstrapped through FAI.
• Puppet does the rest.
Why
Friday, February 1, 13
• Puppet: 0.25 - 2.6.
• Puppet changing at a rapid pace.
• Our manifests growing exponentially.
• Manifests, modules, nodes, argh.
Early days
Friday, February 1, 13
• Limited knowledge on creating Puppet modules.
• Sparse information on how to create good modules.
• Difficult to separate logic from data.
• Lots and lots of nagios hosts, services and checks.
Growing
Friday, February 1, 13
© Jose CP, http://www.flickr.com/photos/andvaranaut/1534670848/Friday, February 1, 13
• Admit you have a problem...
• Take time to fix it!
• Introduce Hiera for data.
• Split modules in small, simple, classes.
• Tests, tests, tests!
Fixing
Friday, February 1, 13
Devil in the details...
Friday, February 1, 13
Testing
class supervisor {package { ‘supervisor’:ensure => latest,
}}
Friday, February 1, 13
Testing
class supervisor {package { ‘supervisor’:ensure => latest,
}}
provider => ‘pip’,
Friday, February 1, 13
Update everything!
class mysql::server {package { ‘mysql-‐server’:
ensure => latest,}
}
Friday, February 1, 13
Update everything!class puppet::agent {
package { ‘puppet’:ensure => latest,
}}class puppet::master {
package { ‘puppetmaster’:ensure => latest,
}}
Friday, February 1, 13
© Joe Mott, http://www.flickr.com/photos/motti82/3778598336/Friday, February 1, 13
Schedule!schedule { 'never':
period => ‘never’,}
class mysql::master {service { ‘mysql’:
schedule => never,}
}
Friday, February 1, 13
We’ve got issues...
Friday, February 1, 13
• Not possible to keep everything in one place
• Duplication of data within a single source
Data
Friday, February 1, 13
• Help people first...
• Then tell them they’re doing it wrong.
Community
Friday, February 1, 13
• Help people first...
• Then tell them they’re doing it wrong.
Community
• 2.7.0 is the first version of Puppet to support Ruby 1.9.
Friday, February 1, 13
Nagios
Friday, February 1, 13
Nagios• Puppet report
• config retrieval: 113.85s
• runtime: 155.21s
Friday, February 1, 13
Nagios
• time puppet agent --onetime --no-daemonize
• real: 23m 28.201s
• user: 21m 9.239s
• sys: 0m 24.026s
• Puppet report
• config retrieval: 113.85s
• runtime: 155.21s
Friday, February 1, 13
rspec-puppet
Friday, February 1, 13
Getting startedsource :rubygemsgem 'puppet', '~> 2.7.20'gem 'facter', '~> 1.6.15'gem 'puppet-‐lint', '~> 0.3.2'gem 'rspec-‐puppet', '~> 0.1.5'gem 'puppetlabs_spec_helper', '~> 0.4.0'
Friday, February 1, 13
Getting started
• Aren’t always up to date
• Not using rspec-‐puppet-‐init
• .fixtures.yml with puppetlabs_spec_helper
Friday, February 1, 13
Scaffolding$ cd modules/modulename
$ mkdir -‐p spec/{defines, classes, functions, hosts, fixtures}
$ echo "require 'puppetlabs_spec_helper/module_spec_helper'" > "spec/spec_helper.rb"
$ echo "require 'puppetlabs_spec_helper/rake_tasks'" > "Rakefile"
Friday, February 1, 13
Scaffolding$ cat .fixtures.yml
fixtures: symlinks: stdlib: "#{source_dir}/../stdlib" webapp: "#{source_dir}"
Friday, February 1, 13
Testing yoloclass yolo { notic { 'yolo': }}
require 'spec_helper'describe 'yolo' do it "should build" do should contain_class('yolo') endend
Friday, February 1, 13
Testing yolorake specFailures: 1) yolo should build Failure/Error: should contain_class('yolo') Puppet::Error: Puppet::Parser::AST::Resource failed with error ArgumentError: Invalid resource type notic at yolo/manifests/init.pp:40
# ./spec/classes/yolo_spec.rb:5Finished in 0.0809 seconds1 example, 1 failure
Friday, February 1, 13
Fail fastclass yolo ( $param = false, ){ validate_string($param)}
require 'spec_helper'describe 'yolo' do it "should build" do should contain_class('yolo') endend
Friday, February 1, 13
Fail fastrake specFailures: 1) yolo should build Failure/Error: should contain_class('yolo') Puppet::Error: false is not a string. It looks to be a FalseClass at yolo/manifests/init.pp:40
# ./spec/classes/yolo_spec.rb:5Finished in 0.0809 seconds1 example, 1 failure
Friday, February 1, 13
Fail moreclass yolo ( $param=false, ){ validate_string($param) if empty($param){ fail(‘Dude, wth, empty?!’) }}
require 'spec_helper'describe 'yolo' dolet :params do { :param => '' } end [..]end
Friday, February 1, 13
Fail morerake specFailures: 1) yolo should build Failure/Error: should contain_class('yolo') Puppet::Error: Dude, wth, empty?! at yolo/manifests/init.pp:43
# ./spec/classes/yolo_spec.rb:5Finished in 0.0809 seconds1 example, 1 failure
Friday, February 1, 13
Check your validationrequire 'spec_helper'
describe 'yolo' do context 'with invalid $param type' do let :params do { :param => {} } end it "should break horribly" do expect { subject }.to raise_error(Puppet::Error, /\{\} is not a string/) end endend
Friday, February 1, 13
Check your validation
rake spec.
Finished in 0.08736 seconds1 example, 0 failures
Friday, February 1, 13
Check your facts
class yolo( $param = $yolo::params::lol) inherits yolo::params {
[do stuff, like validation]
}
Friday, February 1, 13
Check your factsclass yolo::params { case $::osfamily { 'Debian': { [set some really fancy variables] }
default: { fail("\$osfamily ${::osfamily} is not supported by the yolo module.") } }}
Friday, February 1, 13
Check your facts describe 'on unsupported' do let :facts do { :osfamily => 'Little Red Riding Hood' } end
it 'should fail' do expect { subject }.to raise_error(/osfamily Little Red Riding Hood is not supported/) end end
Friday, February 1, 13
Check your resources
class yolo::configs { file { $f_yolo_default: # Template uses $interfaces content => template('yolo/default.erb'), }}
Friday, February 1, 13
Check your resources
describe 'yolo::configs' do let :params do { :f_yolo_default => '/etc/default/yolo',} end
it do should contain_file('/etc/default yolo').with_content(/CATS="lol"/) endend
Friday, February 1, 13
Matchers
• For every resource: contain_resource()
• For every attribute: with_attr(‘value’)
• Or: with({:attr1 => ‘value1’, :attr2 => ‘value2’})
• Check the content: with_content(regex)
• include_class()
Friday, February 1, 13
Helpers
•let :params do { :param => {} } end
•let :facts do { :osfamily => ‘’ } end
•let :pre_condition do 'include class::we::need' end
Friday, February 1, 13
© Vinoth Chandar, http://www.flickr.com/photos/vinothchandar/4278047231/Friday, February 1, 13