SlideShare a Scribd company logo
What Makes a Good
Cookbook?
Julian C. Dunn
Senior Consulting Engineer Engineering Team Lead
Chef Software, Inc.
<jdunn@getchef.com>
$ whoami
• Consulting Engineer
Engineering Team Lead at Chef
• System Administrator
• Reformed Java Developer
• Writes silly code like this
•https://github.com/juliandunn/
doge-chef-formatter
Finding a Good Cookbook
LMGTCFY
What Makes a Good Chef Cookbook? (May 2014 Edition)
Do judge a cookbook by its cover
What Makes a Good Chef Cookbook? (May 2014 Edition)
What Makes a Good Chef Cookbook? (May 2014 Edition)
What Makes a Good Chef Cookbook? (May 2014 Edition)
What Makes a Good Chef Cookbook? (May 2014 Edition)
missing_attrs = %w{
postgres
}.select do |attr|
node['postgresql']['password'][attr].nil?
end.map { |attr| "node['postgresql']['password']['#{attr}']" }
if !missing_attrs.empty?
Chef::Application.fatal!([
"You must set #{missing_attrs.join(', ')} in chef-solo mode.",
"For more information, see https://github.com/opscode-
cookbooks/postgresql#chef-solo-note"
].join(' '))
end
Too Clever for Its Own Good
Chef::Application.fatal!([
"You must set #{missing_attrs.join(', ')} in chef-solo mode.",
"For more information, see https://github.com/opscode-
cookbooks/postgresql#chef-solo-note"
].join(' '))
Poking at Chef Internals
• Other abuses: Messing with run_context and
run_state
if node.run_list.recipes.include?('foo::bar')
...
end
Poking run_list and environment
if node.chef_environment == 'production'
...
end
• Use feature flags!
template "/etc/whatever.conf" do
...
not_if { foo }
end
Compile vs. Execute Errors
if foo
template "/etc/whatever.conf" do
...
end
end
not the same thing as
execute 'yum install httpd' do
not_if 'rpm -qa | grep -x httpd'
end
Not declarative
• Also, the Chef recipe with 100 bash or
powershell_script resource declarations
execute '/i/will/run/every/time' do
action :run
# because I don't have a guard here
end
Missing guards
default['mydaemon']['port'] = '1433'
# don't you mean the integer 1433?
default['mydaemon']['knob'] = 'disabled'
# don't you mean false?
Not using native Ruby data types
• If you use native data types you can validate
people’s input.
Fear of LWRPs
• Missed abstraction opportunities
• No good example to put here; they’re all 200 lines
long (thus proving my point)
remote_file 'whatever.tar.gz' do
source 'http://hardcoded.url.com/'
end
Hardcoded Strings
Excess Conditions & Recipe Length
• https://github.com/opscode-
cookbooks/mysql/blob/v3.0.12/recipes/server.rb
• (We’ve since refactored this)
Good Cookbooks...
Put control flow in attributes
• Especially for cross-platform cookbooks
• Set common set of attributes, write common
behavior in recipe context
case node['platform']
when "debian", "ubuntu"
default['postgresql']['client']['packages'] = %w{postgresql-client libpq-dev}
default['postgresql']['server']['packages'] = %w{postgresql}
default['postgresql']['contrib']['packages'] = %w{postgresql-contrib}
when "fedora", "amazon"
default['postgresql']['client']['packages'] = %w{postgresql-devel}
default['postgresql']['server']['packages'] = %w{postgresql-server}
default['postgresql']['contrib']['packages'] = %w{postgresql-contrib}
default['postgresql']['server']['service_name'] = "postgresql"
when "redhat", "centos", "scientific", "oracle"
default['postgresql']['version'] = "8.4"
default['postgresql']['dir'] = "/var/lib/pgsql/data"
if node['platform_version'].to_f >= 6.0
default['postgresql']['client']['packages'] = %w{postgresql-devel}
default['postgresql']['server']['packages'] = %w{postgresql-server}
default['postgresql']['contrib']['packages'] = %w{postgresql-contrib}
else
default['postgresql']['client']['packages'] = ["postgresql#{node['postgresql']['version'].split('.').join}-devel"]
default['postgresql']['server']['packages'] = ["postgresql#{node['postgresql']['version'].split('.').join}-server"]
default['postgresql']['contrib']['packages'] = ["postgresql#{node['postgresql']['version'].split('.').join}-contrib"]
end
default['postgresql']['server']['service_name'] = "postgresql"
Control Flow in Attributes
node['postgresql']['server']['packages'].each do |pg_pack|
package pg_pack
end
Common Recipe Code
• Easy to support more platforms without modifying
recipe
default.rb
server.rb
_suse.rb_fedora.rb_windows.rb
Separate recipes by OS
• If things you do are very different per platform,
separate them into different recipes
“Public” versus “Private” recipes
• ‘_’ faux-namespacing
loaded_recipes = if run_context.respond_to?(:loaded_recipes)
run_context.loaded_recipes
else
node.run_state[:seen_recipes]
end
node['mysql']['client']['packages'].each do |name|
resources("package[#{name}]").run_action(:install)
end
Do not abuse compile-time
•.run_action(:must_die)
• Use sparingly, if at all!
if some_error_condition
fail "Helpful error message"
# rather than Chef::Application.fatal!("error")
end
Avoid poking Chef Internals
•Chef::Application.fatal is for use by Chef
itself
•fail or raise is better
Attributes only where necessary
• “Let’s create a node attribute for each of the 15,000
tunables in this daemon”
• Not necessary if you never touch 14,975 of those
knobs
git clone git://github.com/foozolix/foozolix.git
cd foozolix && ./configure
make
make install
Give people options for installation
• At least give people a way to install from packages.
• “Compile from source” should be banned in most
cases.
Be declarative
• Know and use built-in Chef resources
• Know where to find LWRPs to avoid
batch/execute/powershell_script
• Consider log resource versus Chef::Log
•Shows up in reporting as an updated resource instead of having to trawl
through client.log
•Set an idempotency guard!
•Log at the right log level
Run System Commands Safely
• system
• backticks
•Chef::Mixin::ShellOut
•shell_out
•shell_out!
$ chef-apply -s
Chef::Recipe.send(:include, Chef::Mixin::ShellOut)
cmd = shell_out!("echo -n Ohai, world")
log cmd.stdout
^D
Recipe: (chef-apply cookbook)::(chef-apply recipe)
* log[Ohai, world] action write
Example Recipe Context
unless node.chef_environment('pigsty')
include_recipe 'bacon::default'
end
Feature Flags Example
if node['foo']['bar']['can_haz_bacon']
include_recipe 'bacon::default'
end
• Instead:
node['jboss']['instances'].each do |instance|
link "/etc/init.d/#{instance['name']}" do
to "/etc/init.d/jbossas"
end
template "/etc/sysconfig/#{instance['name']}" do
source "jbossas.sysconfig.erb"
owner node['jboss']['server']['user']
group node['jboss']['server']['group']
mode "00644"
variables(
:jbossconf => instance['name']
)
action :create
end
template "#{node['jboss']['server']['home']}/bin/standalone.sh" do
source "standalone.sh.erb"
owner node['jboss']['server']['user']
group node['jboss']['server']['group']
mode "00755"
action :create
end
link "#{node['jboss']['server']['home']}/bin/#{instance['name']}.sh" do
to "#{node['jboss']['server']['home']}/bin/standalone.sh"
end
end
Repetition == LWRP Candidate
actions :create, :delete
attribute :instance_name, :kind_of => String, :name_attribute => true
attribute :console_log_level, :kind_of => String, :required => true
attribute :datasources, :kind_of => Hash, :default => {}
.
.
.
default_action :create
Repetition == LWRP Candidate
• Perfect for abstracting!
• Resource interface:
jboss_instance "petstore" do
instance_name "can_haz_cheezburgerz"
console_log_level "DEBUG"
datasources {'db1' => 'jdbc://whatever:5432/db1'}
end
Repetition == LWRP Candidate
• Write/debug hard logic once
• Clear consumer interface
• Parameter validation & sanity checking
• Non-JBoss experts can invoke without knowing gnarly details
module MyCookbook
module Helper
# returns Windows friendly version of the provided path,
# ensures backslashes are used everywhere
def win_friendly_path(path)
path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR) if path
end
end
end
Write helper libraries
• Create reusable helper functions in pure Ruby
• Move repetitive detail out of recipe context.
• http://tinyurl.com/chef-libraries
Keep Recipes Small
• < 100 lines
• If longer than this, consider breaking up functionality
• Example: nagios::server recipe does too much
•Installs Nagios
•Configures Nagios
•Pokes around in data bags for config items
Use Community Helpers
• Chef Sugar - http://code.sethvargo.com/chef-sugar/
• Chef Cutlery - https://github.com/realityforge/chef-cutlery
• Attribute Validator -
https://github.com/clintoncwolfe/attribute-validator
• You can also crib the ideas if you want to avoid external
dependencies
Wrap-Up
Testing
• I didn’t mention testing once in this talk!
• I’m assuming you will write tests for your cookbooks.
• A whole other talk...
• ... including good/bad things to test
Make your code aromatic
• Keep recipes small
• Keep recipes simple
• Use a consistent style
• Use Foodcritic
Beware Expertise Bias
• Hide gnarly details from recipe context
•Libraries
•LWRPs
•Attributes
• Resist urge to be overly clever - not everyone’s an expert
•Akin to the one-line sed/awk script
•http://tinyurl.com/the-expertise-bias
Learn from Software Developers
• Everything I told you about information hiding, design
patterns, testing, etc.
• Ops can learn from devs as well!
• Maybe we should call it OpsDev...
Don’t Yet Know Chef?
• 2-Day Chef Fundamentals
Training in Boston
• June 16-17
• New Horizons, 75 Federal
St., Suite 1205
• Use code MEETUP to save
10%
Thank You!
E: jdunn@getchef.com
G: https://github.com/juliandunn
T: @julian_dunn
W: www.juliandunn.net
What Makes a Good Chef Cookbook? (May 2014 Edition)

More Related Content

PPTX
Configuration Management in a Containerized World
PDF
Tips and Tricks for Automating Windows with Chef
PPTX
Orchestration? You Don't Need Orchestration. What You Want is Choreography.
PDF
Cooking on Windows without the Windows Cookbook
PPT
Cooking with Chef on Windows
PPTX
Cooking with Chef on Windows: 2015 Edition
PPTX
Automating That "Other" OS
PDF
Getting Started with Ansible
Configuration Management in a Containerized World
Tips and Tricks for Automating Windows with Chef
Orchestration? You Don't Need Orchestration. What You Want is Choreography.
Cooking on Windows without the Windows Cookbook
Cooking with Chef on Windows
Cooking with Chef on Windows: 2015 Edition
Automating That "Other" OS
Getting Started with Ansible

What's hot (20)

PDF
Infrastructure = Code
PDF
Cookbook testing with KitcenCI and Serverrspec
ODP
Chef training - Day2
ODP
Chef training - Day3
ODP
Chef training Day5
ODP
Chef training Day4
PPTX
Monitoring and tuning your chef server - chef conf talk
PDF
Leveraging Ansible for CI/CD
PDF
Ansible new paradigms for orchestration
PDF
Ansible Introduction
PPTX
Docker ansible-make-chef-puppet-unnecessary-minnihan
PDF
Deploying an application with Chef and Docker
PDF
Continuous infrastructure testing
PDF
Testable Infrastructure with Chef, Test Kitchen, and Docker
PPTX
Ansible Automation Best Practices From Startups to Enterprises - Minnebar 12
PDF
Chef for beginners module 5
PDF
Introduction to Ansible
PDF
Zero Downtime Deployment with Ansible
PPTX
Chef introduction
PDF
Infrastructure testing with Jenkins, Puppet and Vagrant - Agile Testing Days ...
Infrastructure = Code
Cookbook testing with KitcenCI and Serverrspec
Chef training - Day2
Chef training - Day3
Chef training Day5
Chef training Day4
Monitoring and tuning your chef server - chef conf talk
Leveraging Ansible for CI/CD
Ansible new paradigms for orchestration
Ansible Introduction
Docker ansible-make-chef-puppet-unnecessary-minnihan
Deploying an application with Chef and Docker
Continuous infrastructure testing
Testable Infrastructure with Chef, Test Kitchen, and Docker
Ansible Automation Best Practices From Startups to Enterprises - Minnebar 12
Chef for beginners module 5
Introduction to Ansible
Zero Downtime Deployment with Ansible
Chef introduction
Infrastructure testing with Jenkins, Puppet and Vagrant - Agile Testing Days ...
Ad

Viewers also liked (9)

PDF
Introduction to Docker & CoreOS - Symfony User Group Cologne
 
PDF
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...
PPTX
Introduction to chef
PDF
Chef Cookbook Testing and Continuous Integration
PDF
Chef Fundamentals Training Series Module 1: Overview of Chef
PDF
Introduction to Chef: Automate Your Infrastructure by Modeling It In Code
PPTX
Jenkins and Chef: Infrastructure CI and Automated Deployment
KEY
Infrastructure Automation with Chef
PDF
Introduction to Chef - Techsuperwomen Summit
Introduction to Docker & CoreOS - Symfony User Group Cologne
 
Chef Fundamentals Training Series Module 3: Setting up Nodes and Cookbook Aut...
Introduction to chef
Chef Cookbook Testing and Continuous Integration
Chef Fundamentals Training Series Module 1: Overview of Chef
Introduction to Chef: Automate Your Infrastructure by Modeling It In Code
Jenkins and Chef: Infrastructure CI and Automated Deployment
Infrastructure Automation with Chef
Introduction to Chef - Techsuperwomen Summit
Ad

Similar to What Makes a Good Chef Cookbook? (May 2014 Edition) (20)

PPT
What Makes a Good Cookbook?
PDF
Practical Chef and Capistrano for Your Rails App
KEY
Cooking with Chef
PDF
Using Test Kitchen for testing Chef cookbooks
PDF
Chef or how to make computers do the work for us
PDF
Custom deployments with sbt-native-packager
PDF
Burn down the silos! Helping dev and ops gel on high availability websites
ODP
DB proxy server test: run tests on tens of virtual machines with Jenkins, Vag...
PDF
Dev ninja -> vagrant + virtualbox + chef-solo + git + ec2
ODP
Configuration management with Chef
PDF
Chef solo the beginning
ZIP
Rails 3 (beta) Roundup
PPTX
DevOps Hackathon: Session 3 - Test Driven Infrastructure
PDF
Automating Complex Setups with Puppet
PPTX
Creating Reusable Puppet Profiles
PDF
Facebook的缓存系统
KEY
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
PDF
Cloud Automation with Opscode Chef
PDF
Chef patterns
KEY
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
What Makes a Good Cookbook?
Practical Chef and Capistrano for Your Rails App
Cooking with Chef
Using Test Kitchen for testing Chef cookbooks
Chef or how to make computers do the work for us
Custom deployments with sbt-native-packager
Burn down the silos! Helping dev and ops gel on high availability websites
DB proxy server test: run tests on tens of virtual machines with Jenkins, Vag...
Dev ninja -> vagrant + virtualbox + chef-solo + git + ec2
Configuration management with Chef
Chef solo the beginning
Rails 3 (beta) Roundup
DevOps Hackathon: Session 3 - Test Driven Infrastructure
Automating Complex Setups with Puppet
Creating Reusable Puppet Profiles
Facebook的缓存系统
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
Cloud Automation with Opscode Chef
Chef patterns
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard

More from Julian Dunn (16)

PPTX
Technical Careers Beyond DevOps
PPTX
Pull, Don't Push! Sensu Summit 2018 Talk
PPTX
Now That I Have Choreography, What Do I Do With It?
PPTX
Distributed systems are hard; distributed systems of people are harder
PPTX
Chef on AIX
PPTX
Chef-NYC Announcements July 2014
PPTX
Chef NYC Users' Group - Announcements for June 2014
PPTX
Improving Your Mac Productivity
PPTX
Chef Cookbook Governance BoF at ChefConf
PPTX
Chef and PowerShell Desired State Configuration
PPT
Configuration Management Isn't Everything
PDF
An Introduction to DevOps with Chef
PDF
ChefConf 2013: Beginner Chef Antipatterns
PPTX
Chef Workflow Strategies at SecondMarket
PDF
What Your CDN Won't Tell You: Optimizing a News Website for Speed and Stability
KEY
An Introduction to Shef, the Chef Shell
Technical Careers Beyond DevOps
Pull, Don't Push! Sensu Summit 2018 Talk
Now That I Have Choreography, What Do I Do With It?
Distributed systems are hard; distributed systems of people are harder
Chef on AIX
Chef-NYC Announcements July 2014
Chef NYC Users' Group - Announcements for June 2014
Improving Your Mac Productivity
Chef Cookbook Governance BoF at ChefConf
Chef and PowerShell Desired State Configuration
Configuration Management Isn't Everything
An Introduction to DevOps with Chef
ChefConf 2013: Beginner Chef Antipatterns
Chef Workflow Strategies at SecondMarket
What Your CDN Won't Tell You: Optimizing a News Website for Speed and Stability
An Introduction to Shef, the Chef Shell

Recently uploaded (20)

PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PPT
Teaching material agriculture food technology
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Electronic commerce courselecture one. Pdf
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Machine learning based COVID-19 study performance prediction
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PPTX
MYSQL Presentation for SQL database connectivity
DOCX
The AUB Centre for AI in Media Proposal.docx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Empathic Computing: Creating Shared Understanding
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Teaching material agriculture food technology
Digital-Transformation-Roadmap-for-Companies.pptx
NewMind AI Weekly Chronicles - August'25 Week I
Spectral efficient network and resource selection model in 5G networks
Chapter 3 Spatial Domain Image Processing.pdf
Electronic commerce courselecture one. Pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Machine learning based COVID-19 study performance prediction
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
MYSQL Presentation for SQL database connectivity
The AUB Centre for AI in Media Proposal.docx
“AI and Expert System Decision Support & Business Intelligence Systems”
Network Security Unit 5.pdf for BCA BBA.
Empathic Computing: Creating Shared Understanding
Building Integrated photovoltaic BIPV_UPV.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
20250228 LYD VKU AI Blended-Learning.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?

What Makes a Good Chef Cookbook? (May 2014 Edition)

  • 1. What Makes a Good Cookbook? Julian C. Dunn Senior Consulting Engineer Engineering Team Lead Chef Software, Inc. <jdunn@getchef.com>
  • 2. $ whoami • Consulting Engineer Engineering Team Lead at Chef • System Administrator • Reformed Java Developer • Writes silly code like this •https://github.com/juliandunn/ doge-chef-formatter
  • 3. Finding a Good Cookbook LMGTCFY
  • 5. Do judge a cookbook by its cover
  • 10. missing_attrs = %w{ postgres }.select do |attr| node['postgresql']['password'][attr].nil? end.map { |attr| "node['postgresql']['password']['#{attr}']" } if !missing_attrs.empty? Chef::Application.fatal!([ "You must set #{missing_attrs.join(', ')} in chef-solo mode.", "For more information, see https://github.com/opscode- cookbooks/postgresql#chef-solo-note" ].join(' ')) end Too Clever for Its Own Good
  • 11. Chef::Application.fatal!([ "You must set #{missing_attrs.join(', ')} in chef-solo mode.", "For more information, see https://github.com/opscode- cookbooks/postgresql#chef-solo-note" ].join(' ')) Poking at Chef Internals • Other abuses: Messing with run_context and run_state
  • 12. if node.run_list.recipes.include?('foo::bar') ... end Poking run_list and environment if node.chef_environment == 'production' ... end • Use feature flags!
  • 13. template "/etc/whatever.conf" do ... not_if { foo } end Compile vs. Execute Errors if foo template "/etc/whatever.conf" do ... end end not the same thing as
  • 14. execute 'yum install httpd' do not_if 'rpm -qa | grep -x httpd' end Not declarative • Also, the Chef recipe with 100 bash or powershell_script resource declarations
  • 15. execute '/i/will/run/every/time' do action :run # because I don't have a guard here end Missing guards
  • 16. default['mydaemon']['port'] = '1433' # don't you mean the integer 1433? default['mydaemon']['knob'] = 'disabled' # don't you mean false? Not using native Ruby data types • If you use native data types you can validate people’s input.
  • 17. Fear of LWRPs • Missed abstraction opportunities • No good example to put here; they’re all 200 lines long (thus proving my point)
  • 18. remote_file 'whatever.tar.gz' do source 'http://hardcoded.url.com/' end Hardcoded Strings
  • 19. Excess Conditions & Recipe Length • https://github.com/opscode- cookbooks/mysql/blob/v3.0.12/recipes/server.rb • (We’ve since refactored this)
  • 21. Put control flow in attributes • Especially for cross-platform cookbooks • Set common set of attributes, write common behavior in recipe context
  • 22. case node['platform'] when "debian", "ubuntu" default['postgresql']['client']['packages'] = %w{postgresql-client libpq-dev} default['postgresql']['server']['packages'] = %w{postgresql} default['postgresql']['contrib']['packages'] = %w{postgresql-contrib} when "fedora", "amazon" default['postgresql']['client']['packages'] = %w{postgresql-devel} default['postgresql']['server']['packages'] = %w{postgresql-server} default['postgresql']['contrib']['packages'] = %w{postgresql-contrib} default['postgresql']['server']['service_name'] = "postgresql" when "redhat", "centos", "scientific", "oracle" default['postgresql']['version'] = "8.4" default['postgresql']['dir'] = "/var/lib/pgsql/data" if node['platform_version'].to_f >= 6.0 default['postgresql']['client']['packages'] = %w{postgresql-devel} default['postgresql']['server']['packages'] = %w{postgresql-server} default['postgresql']['contrib']['packages'] = %w{postgresql-contrib} else default['postgresql']['client']['packages'] = ["postgresql#{node['postgresql']['version'].split('.').join}-devel"] default['postgresql']['server']['packages'] = ["postgresql#{node['postgresql']['version'].split('.').join}-server"] default['postgresql']['contrib']['packages'] = ["postgresql#{node['postgresql']['version'].split('.').join}-contrib"] end default['postgresql']['server']['service_name'] = "postgresql" Control Flow in Attributes
  • 23. node['postgresql']['server']['packages'].each do |pg_pack| package pg_pack end Common Recipe Code • Easy to support more platforms without modifying recipe
  • 24. default.rb server.rb _suse.rb_fedora.rb_windows.rb Separate recipes by OS • If things you do are very different per platform, separate them into different recipes
  • 25. “Public” versus “Private” recipes • ‘_’ faux-namespacing
  • 26. loaded_recipes = if run_context.respond_to?(:loaded_recipes) run_context.loaded_recipes else node.run_state[:seen_recipes] end node['mysql']['client']['packages'].each do |name| resources("package[#{name}]").run_action(:install) end Do not abuse compile-time •.run_action(:must_die) • Use sparingly, if at all!
  • 27. if some_error_condition fail "Helpful error message" # rather than Chef::Application.fatal!("error") end Avoid poking Chef Internals •Chef::Application.fatal is for use by Chef itself •fail or raise is better
  • 28. Attributes only where necessary • “Let’s create a node attribute for each of the 15,000 tunables in this daemon” • Not necessary if you never touch 14,975 of those knobs
  • 29. git clone git://github.com/foozolix/foozolix.git cd foozolix && ./configure make make install Give people options for installation • At least give people a way to install from packages. • “Compile from source” should be banned in most cases.
  • 30. Be declarative • Know and use built-in Chef resources • Know where to find LWRPs to avoid batch/execute/powershell_script • Consider log resource versus Chef::Log •Shows up in reporting as an updated resource instead of having to trawl through client.log •Set an idempotency guard! •Log at the right log level
  • 31. Run System Commands Safely • system • backticks •Chef::Mixin::ShellOut •shell_out •shell_out!
  • 32. $ chef-apply -s Chef::Recipe.send(:include, Chef::Mixin::ShellOut) cmd = shell_out!("echo -n Ohai, world") log cmd.stdout ^D Recipe: (chef-apply cookbook)::(chef-apply recipe) * log[Ohai, world] action write Example Recipe Context
  • 33. unless node.chef_environment('pigsty') include_recipe 'bacon::default' end Feature Flags Example if node['foo']['bar']['can_haz_bacon'] include_recipe 'bacon::default' end • Instead:
  • 34. node['jboss']['instances'].each do |instance| link "/etc/init.d/#{instance['name']}" do to "/etc/init.d/jbossas" end template "/etc/sysconfig/#{instance['name']}" do source "jbossas.sysconfig.erb" owner node['jboss']['server']['user'] group node['jboss']['server']['group'] mode "00644" variables( :jbossconf => instance['name'] ) action :create end template "#{node['jboss']['server']['home']}/bin/standalone.sh" do source "standalone.sh.erb" owner node['jboss']['server']['user'] group node['jboss']['server']['group'] mode "00755" action :create end link "#{node['jboss']['server']['home']}/bin/#{instance['name']}.sh" do to "#{node['jboss']['server']['home']}/bin/standalone.sh" end end Repetition == LWRP Candidate
  • 35. actions :create, :delete attribute :instance_name, :kind_of => String, :name_attribute => true attribute :console_log_level, :kind_of => String, :required => true attribute :datasources, :kind_of => Hash, :default => {} . . . default_action :create Repetition == LWRP Candidate • Perfect for abstracting! • Resource interface:
  • 36. jboss_instance "petstore" do instance_name "can_haz_cheezburgerz" console_log_level "DEBUG" datasources {'db1' => 'jdbc://whatever:5432/db1'} end Repetition == LWRP Candidate • Write/debug hard logic once • Clear consumer interface • Parameter validation & sanity checking • Non-JBoss experts can invoke without knowing gnarly details
  • 37. module MyCookbook module Helper # returns Windows friendly version of the provided path, # ensures backslashes are used everywhere def win_friendly_path(path) path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR) if path end end end Write helper libraries • Create reusable helper functions in pure Ruby • Move repetitive detail out of recipe context. • http://tinyurl.com/chef-libraries
  • 38. Keep Recipes Small • < 100 lines • If longer than this, consider breaking up functionality • Example: nagios::server recipe does too much •Installs Nagios •Configures Nagios •Pokes around in data bags for config items
  • 39. Use Community Helpers • Chef Sugar - http://code.sethvargo.com/chef-sugar/ • Chef Cutlery - https://github.com/realityforge/chef-cutlery • Attribute Validator - https://github.com/clintoncwolfe/attribute-validator • You can also crib the ideas if you want to avoid external dependencies
  • 41. Testing • I didn’t mention testing once in this talk! • I’m assuming you will write tests for your cookbooks. • A whole other talk... • ... including good/bad things to test
  • 42. Make your code aromatic • Keep recipes small • Keep recipes simple • Use a consistent style • Use Foodcritic
  • 43. Beware Expertise Bias • Hide gnarly details from recipe context •Libraries •LWRPs •Attributes • Resist urge to be overly clever - not everyone’s an expert •Akin to the one-line sed/awk script •http://tinyurl.com/the-expertise-bias
  • 44. Learn from Software Developers • Everything I told you about information hiding, design patterns, testing, etc. • Ops can learn from devs as well! • Maybe we should call it OpsDev...
  • 45. Don’t Yet Know Chef? • 2-Day Chef Fundamentals Training in Boston • June 16-17 • New Horizons, 75 Federal St., Suite 1205 • Use code MEETUP to save 10%
  • 46. Thank You! E: jdunn@getchef.com G: https://github.com/juliandunn T: @julian_dunn W: www.juliandunn.net