Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TDD your Puppet Modules

TDD your Puppet Modules

This short talk will briefly show you how you can test your puppet modules. The talk was given @kaufda office on the 22th of January, 2014. More infos under http://www.meetup.com/Puppet-User-Group-Berlin/events/145643562/

Dc708e96bc09d605a0a9fcad26ff6035?s=128

Matthias Günther

January 22, 2014
Tweet

Transcript

  1. TDD your Puppet Modules Testing is necessary Matthias Günther (@wikimatze)

  2. Testing like a dummy

  3. Tools puppet cucumber puppet-lint rspec-puppet

  4. Cucumber Feature: Catalog policy In order to ensure basic correctness

    I want all catalogs to obey my policy Scenario Outline: Generic policy for all server roles Given a node with role "<server_role>" When I compile its catalog Then compilation should succeed And puppet should ensure all packages are up-to-date Examples: | server_role | | dhcp_server |
  5. puppet-lint # manifests/init.pp class git::init { include git:: package }

  6. Running puppet-lint $ puppet-lint manifests/init.pp ERROR: two-space soft tabs not

    used on line 10 WARNING: unquoted resource title on line 10
  7. Modules

  8. Puppet module structure |-- manifests | |-- init.pp | |--

    package.pp | `-- params.pp |-- Rakefile `-- spec |-- classes |-- defines |-- fixtures | |-- manifests | | `-- site.pp | `-- modules | `-- git | `-- manifests -> ../../../../manifests |-- functions |-- hosts `-- spec_helper.rb
  9. RSpec Test # spec/classes/init_spec.pp require 'spec_helper' describe "git::init" do it

    { should create_class('git::package') } end
  10. Running the test $ rake spec git::init example at ./spec/classes/init_spec.rb:4

    (FAILED - 1) Failures: 1) git::init Failure/Error: it { should create_class('git::install')} Puppet::Error: Could not find class git::init # ./spec/classes/init_spec.rb:4:in `block Finished in 0.20564 seconds 1 examples, 1 failure
  11. Code to pass the test class git::init { include git::install

    }
  12. Cool

  13. Jenkins module: installation # === Authors # # * Matthias

    Günther <mailto:guenther@myhammer.de> # class jenkins::installation { exec{ 'update system before jenkins installation': command => 'apt-get update', require => Class[Jenkins::Setup], } exec{ 'install jenkins': command => 'sudo apt-get install jenkins -y', require => Exec['update system before jenkins installation'], } }
  14. Jenkins module: installation spec require 'spec_helper' describe "jenkins::installation" do it

    { should contain_exec('update system before jenkins installation').with( 'command' => 'apt-get update' ) } it do should contain_exec("install jenkins").with( 'command' => 'sudo apt-get install jenkins -y', 'require' => "Exec[update system before jenkins installation]" ) end end
  15. Enable lint task require 'rspec/core/rake_task' require 'puppet-lint/tasks/puppet-lint' RSpec::Core::RakeTask.new(:spec) do |t|

    t.pattern = 'spec/*/*_spec.rb' end task :default => %w(spec lint)
  16. Running lint $ rake apache2::init ... Finished in 1.45 seconds

    7 examples, 0 failures manifests/package.pp - WARNING: class not documented on line 1
  17. Get rid of certain line warnings PuppetLint.configuration.send("disable_80chars") PuppetLint.configuration.send("disable_documentation")

  18. Overview of all our modules ~/git/development(master ✔) ls ant composer

    dev_user hosts lessc myhammer_directories npm_packages php rabbitmq_myhammer_config shellscripts sysctl vcs_user_key apache credentials faxchecker htop libcurl3 mysql_client ntpdate php5_geoip remove_existing_repositories.sh ssh_keys timezone vim api-apache2 cronolog freetds_bin imagemagick mailsystem ngrep openjdk_jdk php_configuration repositories.txt stdlib tinyproxy apt crons_qa git jstestdriver mc nodejs openjdk_jre puppetfix rsync subversion update_repositories_cron_script.sh build.xml developmentresolve git_repositories_import.sh lcov memcached npm pear rabbitmq ruby symlinks varnish => manageable <=
  19. Continous Integration

  20. We use Jenkins …

  21. … with script trigger

  22. The content of the script #!/bin/bash -x REPOS=`ls -d /mnt/revo/jenkins/jobs/Puppet/workspace/*/`;

    for repo in $REPOS do cd $repo; echo $repo; remote=$(git ls-remote -h origin master | awk '{print $1}') local=$(git rev-parse HEAD) printf "Local : %s\nRemote: %s\n" $local $remote if [ $local == $remote ]; then echo "Commits match." else echo "Changes available => run test." exit 1; fi cd .. done
  23. Summary your arms => rspec- puppet your eyes => lint

    your ears => jenkins
  24. Refactor your specs require 'spec_helper' describe "jenkins::plugins" do let (:base_url)

    { 'http://updates.jenkins-ci.org/download/plugins/' } let (:destination) { '/home/vagrant' } it do should contain_exec('get active-directory').with( 'command' => "sudo wget #{base_url}active-directory/1.33/active-directory.hpi -P #{destination}" ) end it do should contain_exec('get ansicolor').with( 'command' => "sudo wget #{base_url}ansicolor/0.3.1/ansicolor.hpi -P #{destination}" ) end it do should contain_exec('get ant').with( 'command' => "sudo wget #{base_url}ant/1.2/ant.hpi -P #{destination}" ) end it do should contain_exec('get claim').with( 'command' => "sudo wget #{base_url}claim/2.2/claim.hpi -P #{destination}" ) end it do should contain_exec('get ci-game').with( 'command' => "sudo wget #{base_url}ci-game/1.19/ci-game.hpi -P #{destination}" ) end it do should contain_exec('get cvs').with( 'command' => "sudo wget #{base_url}cvs/2.9/cvs.hpi -P #{destination}" ) end it do should contain_exec('get analysis-core').with( 'command' => "sudo wget #{base_url}analysis-core/1.49/analysis-core.hpi -P #{destination}" ) end it do should contain_exec('get beer').with( 'command' => "sudo wget #{base_url}beer/1.2/beer.hpi -P #{destination}" ) end it do should contain_exec('get buildtriggerbadge').with( 'command' => "sudo wget #{base_url}buildtriggerbadge/1.0/buildtriggerbadge.hpi -P #{destination}" ) end it do should contain_exec('get chucknorris').with( 'command' => "sudo wget #{base_url}chucknorris/0.5/chucknorris.hpi -P #{destination}" ) end it do should contain_exec('get credentials').with( 'command' => "sudo wget #{base_url}credentials/1.4/credential.hpi -P #{destination}" ) end it do should contain_exec('get dashboard view').with( 'command' => "sudo wget #{base_url}dashboard-view/2.7/dashboard-view.hpi -P #{destination}" ) end it do should contain_exec('get dry').with( 'command' => "sudo wget #{base_url}dry/2.34/dry.hpi -P #{destination}" ) end it do should contain_exec('get checkstyle').with( 'command' => "sudo wget #{base_url}checkstyle/3.35/checkstyle.hpi -P #{destination}" ) end it do should contain_exec('get cloverphp').with( 'command' => "sudo wget #{base_url}cloverphp/0.3.3/cloverphp.hpi -P #{destination}" ) end it do should contain_exec('get javadoc').with( 'command' => "sudo wget #{base_url}javadoc/1.1/javadoc.hpi -P #{destination}" ) end it do should contain_exec('get plot').with( 'command' => "sudo wget #{base_url}plot/1.5/plot.hpi -P #{destination}" ) end it do should contain_exec('get groovy-postbuild').with( 'command' => "sudo wget #{base_url}groovy-postbuild/1.8/groovy-postbuild.hpi -P #{destination}" ) end it do should contain_exec('get htmlpublisher').with( 'command' => "sudo wget #{base_url}htmlpublisher/1.2/htmlpublisher.hpi -P #{destination}" ) end it do should contain_exec('get gcm-notification').with( 'command' => "sudo wget #{base_url}gcm-notification/1.0/gcm-notification.hpi -P #{destination}" ) end it do should contain_exec('get thinBackup').with( 'command' => "sudo wget #{base_url}thinBackup/1.7.2/thinBackup.hpi -P #{destination}" ) end it do should contain_exec('get greenballs').with( 'command' => "sudo wget #{base_url}greenballs/1.12/greenballs.hpi -P #{destination}" ) end it do should contain_exec('get trac').with( 'command' => "sudo wget #{base_url}trac/1.13/trac.hpi -P #{destination}" ) end it do should contain_exec('get external-monitor-job').with( 'command' => "sudo wget #{base_url}external-monitor-job/1.1/external-monitor-job.hpi -P #{destination}" ) end it do should contain_exec('get git').with( 'command' => "sudo wget #{base_url}git/1.4.0/git.hpi -P #{destination}" ) end it do should contain_exec('get xfpanel').with( 'command' => "sudo wget #{base_url}xfpanel/1.2.2/xfpanel.hpi -P #{destination}" ) end it do should contain_exec('get git-parameter').with( 'command' => "sudo wget #{base_url}git-parameter/0.2/git-parameter.hpi -P #{destination}" ) end it do should contain_exec('get git-client').with( 'command' => "sudo wget #{base_url}git-client/1.0.7/git-client.hpi -P #{destination}" ) end it do should contain_exec('get dry').with( 'command' => "sudo wget #{base_url}dry/2.34/dry.hpi -P #{destination}" ) end it do should contain_exec('get jdepend').with( 'command' => "sudo wget #{base_url}jdepend/1.2.3/jdepend.hpi -P #{destination}" ) end it do should contain_exec('get pmd').with( 'command' => "sudo wget #{base_url}pmd/3.34/pmd.hpi -P #{destination}" ) end it do should contain_exec('get global-build-stats').with( 'command' => "sudo wget #{base_url}global-build-stats/1.3/global-build-stats.hpi -P #{destination}" ) end it do should contain_exec('get instant-messaging').with( 'command' => "sudo wget #{base_url}instant-messaging/1.25/instant-messaging.hpi -P #{destination}" ) end it do should contain_exec('get dry').with( 'command' => "sudo wget #{base_url}dry/2.34/dry.hpi -P #{destination}" ) end it do should contain_exec('get jquery').with( 'command' => "sudo wget #{base_url}jquery/1.7.2-1/jquery.hpi -P #{destination}" ) end it do should contain_exec('get mailer').with( 'command' => "sudo wget #{base_url}mailer/1.5/mailer.hpi -P #{destination}" ) end it do should contain_exec('get sonar').with( 'command' => "sudo wget #{base_url}sonar/2.1/sonar.hpi -P #{destination}" ) end it do should contain_exec('get sonar').with( 'command' => "sudo wget #{base_url}sonar/2.1/sonar.hpi -P #{destination}" ) end it do should contain_exec('get subversion').with( 'command' => "sudo wget #{base_url}subversion/1.50/subversion.hpi -P #{destination}" ) end it do should contain_exec('get translation').with( 'command' => "sudo wget #{base_url}translation/1.10/translation.hpi -P #{destination}" ) end it do should contain_exec('get jenkinswalldisplay').with( 'command' => "sudo wget #{base_url}jenkinswalldisplay/0.6.17/jenkinswalldisplay.hpi -P #{destination}" ) end it do should contain_exec('get jira').with( 'command' => "sudo wget #{base_url}jira/1.36/jira.hpi -P #{destination}" ) end it do should contain_exec('get ldap').with( 'command' => "sudo wget #{base_url}ldap/1.5/ldap.hpi -P #{destination}" ) end it do should contain_exec('get maven-plugin').with( 'command' => "sudo wget #{base_url}maven-plugin/1.519/maven-plugin.hpi -P #{destination}" ) end it do should contain_exec('get pam-auth').with( 'command' => "sudo wget #{base_url}pam-auth/1.1/pam-auth.hpi -P #{destination}" ) end it do should contain_exec('get plot').with( 'command' => "sudo wget #{base_url}plot/1.5/plot.hpi -P #{destination}" ) end it do should contain_exec('get ssh-credentials').with( 'command' => "sudo wget #{base_url}ssh-credentials/0.4/ssh-credentials.hpi -P #{destination}" ) end it do should contain_exec('get ssh-slaves').with( 'command' => "sudo wget #{base_url}ssh-slaves/0.27/ssh-slaves.hpi -P #{destination}" ) end it do should contain_exec('get tasks').with( 'command' => "sudo wget #{base_url}tasks/4.36/tasks.hpi -P #{destination}" ) end it do should contain_exec('get test-stability').with( 'command' => "sudo wget #{base_url}test-stability/1.0/test-stability.hpi -P #{destination}" ) end it do should contain_exec('get violations').with( 'command' => "sudo wget #{base_url}violations/0.7.11/violations.hpi -P #{destination}" ) end it do should contain_exec('get xunit').with( 'command' => "sudo wget #{base_url}xunit/1.60/xunit.hpi -P #{destination}" ) end it do should contain_exec('move plugins into /var/lib/jenkins/plugins').with( 'command' => 'sudo mv /home/vagrant/*.hpi /var/lib/jenkins/plugins/' ) end it do should contain_exec('restart jenkins').with( 'command' => 'service jenkins restart', 'require' => "Exec[move plugins into /var/lib/jenkins/plugins]" ) end end
  25. Pic Credits I Testing like a dummy by lincolnblues: http://

    www.flickr.com/photos/ lincolnblues/1413187481 Modules by Mike Mozart: http://www.flickr.com/photos/ jeepersmedia/11884693514
  26. Pic Credits II Cool by Wally Gobetz: http://www.flickr.com/photos/ wallyg/8779127308 Continous

    Integration by susan: http://www.flickr.com/ photos/ certified_su/229016531/
  27. Pic Credits III We use Jenkins by Matthias Günther: http://

    www.flickr.com/photos/ wikimatze/12072648986 Script Trigger by Matthias Günther: http:// www.flickr.com/photos/ wikimatze/12072648136
  28. About def talks "wikimatze.de/talks" end def twitter @wikimatze end def

    usergroup "vimberlin.de" end def book "padrinobook.com" end def github "matthias-guenther" end