Building Reusable Puppet Modules

2,923
-1

Published on

"Building Reusable Puppet Modules" by Jon Topper at Puppet Camp London 2013. Find a Puppet Camp near you: https://puppetlabs.com/community/puppet-camp/

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,923
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
26
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Building Reusable Puppet Modules

  1. 1. Building Reusable Modules Jon TopperTuesday, 2 April 13
  2. 2. Jon who? ★ 12 years professional Linux sysadmin experience ★ Principal Consultant, The Scale Factory ★ 4.5 years using Puppet (since 0.24) ★ 4 full-time staff + subcontractors ★ >20 customer infrastructures deployedTuesday, 2 April 13
  3. 3. Our Problem Domain ★ Multiple customers ★ Multiple Linux distributions ★ Multiple application environments ★ Adding new features over time ★ Requirement to support old deployments ★ Multiple individuals contributingTuesday, 2 April 13
  4. 4. Your Problem Domain? ★ Multiple teams in a large organisation ★ Forge contributionsTuesday, 2 April 13
  5. 5. Our Approach role_web role_db role_lb defaults yum firewall apache mysql varnish firewall stdlib concatTuesday, 2 April 13
  6. 6. Reusable? ★ Use the same modules ★ In different combinations ★ To solve different problems ★ Without modificationTuesday, 2 April 13
  7. 7. Single Responsibility Install MySQL Configure MySQL Start MySQL ✔ Install MySQL Configure MySQL Install Apache Install mod_php Install Wordpress Configure MySQL grants Configure Wordpress ✘Tuesday, 2 April 13
  8. 8. Low Coupling ★ Changes in highly coupled modules necessitate changes in others ★ Limit coupling where possible ★ Examples of coupling: ★ Using variables from another class ★ Requiring specific resources from another class ★ Any other use of non-public interfacesTuesday, 2 April 13
  9. 9. # sf_apache/manifests/init.pp class sf_apache::service { service { “httpd”: ensure => running } } # sf_puppetmaster/manifests/init.pp class sf_puppetmaster::config { file { “/etc/httpd/conf.d/puppetmaster.conf”: notify => Class[“sf_apache::service”], } } ✔ file { “/etc/httpd/conf.d/puppetmaster.conf”: notify => Service[“httpd”], } ✘Tuesday, 2 April 13
  10. 10. Tell, Don’t Ask class apache::config( $port = 80 ) { ... } ✔ class apache::config { case $hostname { /devel/: { $port = 8080 } default: { $port = 80 } } ... } ✘Tuesday, 2 April 13
  11. 11. Tell, Don’t Ask: Exception class apache::params { case $osfamily { RedHat: { $conf_d_path = "/etc/httpd/conf.d" $user = apache } Debian: { $conf_d_path = "/etc/apache2/conf.d" $user = www-data } } } ✔Tuesday, 2 April 13
  12. 12. Parameters ★ Check user parameters for syntax ★ Choose sensible defaults ★ Document the module’s public interface ★ Write tests for that interfaceTuesday, 2 April 13
  13. 13. Open/Closed Principle ★ Modules should be open for extension ★ But closed for modification ★ Ensures backward compatibility ★ Tests prove that compatibilityTuesday, 2 April 13
  14. 14. Open/Closed Principle define sf_firewall::basic( $proto, $dport = undef, $source = undef, $destination = undef, $action, ){ # Create a basic firewall rule # Assumes ‘INPUT’ chain }Tuesday, 2 April 13
  15. 15. Open/Closed Principle define sf_firewall::basic( $proto, $dport = undef, $source = undef, $destination = undef, $action, $chain, ){ # Create a basic firewall rule. Chain now # a required parameter with no default } ✘Tuesday, 2 April 13
  16. 16. Open/Closed Principle define sf_firewall::basic( $proto, $dport = undef, $source = undef, $destination = undef, $action, $chain = ‘INPUT’ ){ # Create a basic firewall rule. Chain now # defaults to ‘INPUT’ but can be changed. } ✔Tuesday, 2 April 13
  17. 17. Automated Test Pipeline ★ Smoke Tests ★ Unit Tests ★ Integration TestsTuesday, 2 April 13
  18. 18. Smoke Testing ★ puppet-lint to enforce house style ★ puppet parser validate to check syntax ★ Evaluate ERB templates to check syntaxTuesday, 2 April 13
  19. 19. Unit Testing: rspec-puppet ★ Rapid feedback testing ★ Can easily target multiple ruby/puppet version combinations ★ Test your module’s behaviour - not Puppet’s ★ Aim for Condition Coverage across behaviour that varies on parameter ★ Doesn’t guarantee that your module will work as planned in the real world!Tuesday, 2 April 13
  20. 20. Condition Coverage class sf_firewall::params { case $osfamily { RedHat: { $persist_command = "/sbin/iptables-save > /etc/sysconfig/iptables" } Debian: { $persist_command = "/sbin/iptables-save > /etc/iptables/rules.v4" } }Tuesday, 2 April 13
  21. 21. Condition Coverage describe ‘sf_firewall’, :type => ‘class’ do def self.test_standard_behaviour ... end context "on a RedHat OS" do let :facts do { :osfamily => RedHat } end it { should contain_exec(persist-firewall).with_command( "/sbin/iptables-save > /etc/sysconfig/iptables" )} test_standard_behaviour endTuesday, 2 April 13
  22. 22. Integration Testing: Cumberbatch ★ Based on Cucumber ★ Uses Vagrant to start virtual machines ★ Runs puppet manifests for real ★ Tests outcomes ★ Rolls back VM state and tries different manifests ★ Does it all again for a different OS version ★ Very slow!Tuesday, 2 April 13
  23. 23. Integration Testing: Cumberbatch Scenario: Basic install of Apache Given there is a running VM called "server" When I apply a puppet manifest containing: """ include cucumber_defaults class { sf_apache: Port => 80, Children => 10 } """ Then a second manifest application should do nothing And there should be 11 processes called “httpd” running And the Apache module “core_module” should be loaded And the Apache module “rpaf_module” should be loaded And a process called “httpd” should be listening on TCP port 80 And a GET request to http://localhost/server-status/ should return an http status of 200Tuesday, 2 April 13
  24. 24. Questions?Tuesday, 2 April 13
  25. 25. Jon Topper jon@scalefactory.com http://www.scalefactory.com/ Twitter: @jtopperTuesday, 2 April 13

×