Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Writing and Publishing Puppet Modules - PuppetConf 2014

2,094 views

Published on

Writing and Publishing Puppet Modules - Colleen Murphy, Puppet Labs

Published in: Technology
  • Be the first to comment

Writing and Publishing Puppet Modules - PuppetConf 2014

  1. 1. Writing and Publishing Puppet Modules Colleen Murphy
  2. 2. Hello Me (then): Student sysadmin at the IT department for Portland State University’s College of Engineering aka The Computer Action Team (TheCAT) github.com/pdxcat forge.puppetlabs. com/pdxcat
  3. 3. Hello Me (now): Module engineer at Puppet Labs
  4. 4. What is a puppet module? ● An encapsulation of configuration for a service ● A structure containing an organized set of puppet code and data ● Analogous to a package, gem, python library ● The place where your code goes
  5. 5. What should a module do? ● Set up a service, such as: ○ ssh ○ mysql ○ apache ○ sudo ● Extend puppet functionality. Examples: ○ puppetlabs/stdlib ○ puppetlabs/concat
  6. 6. The strategy Set up the service… without puppet. Then iterate.
  7. 7. Layout of a module yourmodule/ ➔ manifests/ # where your puppet code goes ➔ files/ # flat configuration files ➔ templates/ # dynamic configuration files ➔ lib/ # plugins: types and providers, functions, | facts, etc ➔ tests/ # smoke tests/example usage ➔ spec/ # automated tests
  8. 8. Layout of a module yourmodule/ ➔ manifests/ # where your puppet code goes ➔ files/ # flat configuration files ➔ templates/ # dynamic configuration files
  9. 9. Layout of a module yourmodule/ ➔ manifests/ # where your puppet code goes ➔ files/ # flat configuration files ➔ templates/ # dynamic configuration files ➔ tests/ # smoke tests/example usage ➔ spec/ # automated tests
  10. 10. Starting out $ puppet module generate cmurphy-ssh && mv cmurphy-ssh ssh $ mkdir ssh/{files,templates}
  11. 11. Writing your first module # manifests/init.pp class ssh { }
  12. 12. Writing your first module # manifests/init.pp class ssh { package { 'openssh-server': ensure => installed, } }
  13. 13. Writing your first module # manifests/init.pp class ssh { package { 'openssh-server': ensure => installed, } file { '/etc/ssh/sshd_config': source => "puppet:///modules/ssh/sshd_config", require => Package['openssh-server'], } }
  14. 14. Writing your first module # ... package { 'openssh-server': ensure => installed, } file { '/etc/ssh/sshd_config': source => "puppet:///modules/ssh/sshd_config", require => Package['openssh-server'], } service { 'ssh': ensure => running, enable => true, subscribe => File['/etc/ssh/sshd_config'], }
  15. 15. Drop in a configuration file # files/sshd_config # Managed by Puppet # What ports, IPs and protocols we listen for Port 22 Protocol 2 # Logging SyslogFacility AUTH LogLevel INFO # Authentication: LoginGraceTime 120 PermitRootLogin no StrictModes yes # ...
  16. 16. Writing your first module # manifests/init.pp class ssh { package { 'openssh-server': ensure => installed, } file { '/etc/ssh/sshd_config': source => "puppet:///modules/ssh/sshd_config", require => Package['openssh-server'], } service { 'ssh': ensure => running, enable => true, subscribe => File['/etc/ssh/sshd_config'], } }
  17. 17. Writing your first module # tests/init.pp include ssh # or # /etc/puppet/manifests/site.pp node default { include ssh }
  18. 18. Needs more portability! No one should have to change your code or your files in order to use your module.
  19. 19. Template your module # templates/sshd_config.erb # Managed by Puppet # What ports, IPs and protocols we listen for Port <%= @port %> Protocol 2 # Logging SyslogFacility <%= @syslog_facility %> LogLevel <%= @log_level %> # Authentication: LoginGraceTime 120 PermitRootLogin <%= @permit_root_login %> StrictModes yes # ...
  20. 20. Template your module # manifests/init.pp class ssh ( $port = 22, $syslog_facility = 'AUTH', $log_level = 'INFO', $permit_root_login = 'no', ) { # ... file { '/etc/ssh/sshd_config': content => template('ssh/sshd_config.erb'), require => Package['openssh-server'], } # ... # tests/init.pp or site.pp # ... class { 'ssh': permit_root_login => 'without-password', }
  21. 21. Templating strategies # manifests/init.pp class ssh ( $ports = [ 22 ], $options = {} ) { # ... file { '/etc/ssh/sshd_config': content => template('ssh/sshd_config.erb'), require => Package['openssh-server'], } # ... # Applying the class class { 'ssh': ports => [ 22, 2222 ], options => { 'PermitRootLogin' => 'no', } }
  22. 22. Templating strategies # templates/sshd_config.erb # Managed by Puppet <% @ports.each do |port| %> Port <%= port %> <% end %> <% @options.each do |k,v| %> <%= k %> <%= v %> <% end %>
  23. 23. Templating strategies ● Take advantage of Include conf.d/* directives file { '/etc/collectd.conf': ensure => present, content => 'Include "conf.d/*.conf"n', } # … define collectd::plugins::exec { file { "${name}.load": path => "${conf_dir}/${name}.conf", content => template('collectd/exec.conf.erb'), } }
  24. 24. Beyond templates ● puppetlabs/concat concat { '/etc/motd': } concat::fragment { 'welcome': target => '/etc/motd', content => 'Welcome to Redhat', order => '01', } concat::fragment { 'legal': # … }
  25. 25. Beyond templates ● puppetlabs/inifile ini_setting { 'puppetdbserver': ensure => present, section => 'main', path => "${puppet_confdir}/puppetdb.conf", setting => 'server', value => $server, } ini_setting { 'puppetdbport': # … }
  26. 26. Beyond Templates ● augeas augeas { 'sshd_config_permit_root_login': context => '/files/etc/ssh/sshd_config', changes => "set PermitRootLogin $permit_root_login", require => File['/etc/ssh/sshd_config'], } ● domcleal/augeasproviders sshd_config { "PermitRootLogin": ensure => present, value => $permit_root_login, }
  27. 27. Smart Parameter Defaults # manifests/params.pp class ssh::params { case $::osfamily { 'Debian': { $ssh_svc = 'ssh' } 'RedHat': { $ssh_svc = 'sshd' } default: { fail("${::osfamily} is not supported.") } } } # manifests/init.pp class ssh ( # ... ) { include ssh::params service { $ssh::params::ssh_svc: ensure => running, enable => true, } # ...
  28. 28. The Forge
  29. 29. Publishing your module metadata.json ● module name ● version (SemVer) ● author ● summary ● source ● issues URL ● operating system support ● dependencies
  30. 30. Publishing your module Use semantic versioning! semver.org Major.Minor.Patch
  31. 31. Publishing your module Changelog ## 2013-12-05 Release 0.10.0 ### Summary: This release adds FreeBSD osfamily support and various other improvements to some mods. ### Features: - Add suPHP_UserGroup directive to directory context - Add support for ScriptAliasMatch directives ... ## 2013-09-06 Release 0.9.0 ### Summary: ...
  32. 32. Publishing your module README ● docs.puppetlabs.com/puppet/3/reference/READMEtemplate.markdown
  33. 33. Publishing your module license ● choosealicense.com
  34. 34. Publishing your module $ cd ssh/ $ puppet module build . $ ls pkg/ cmurphy-ssh-0.0.1 cmurphy-ssh-0.0.1.tar.gz
  35. 35. Testing Why we test: ● Testing gives us (some) assurance that our code won’t break production systems ● Contributors can run tests without having the same infrastructure as you
  36. 36. Testing your module ● Smoke testing # puppet apply --noop tests/init.pp
  37. 37. Testing your module ● Unit testing: rspec-puppet ○ rspec-puppet.com $ bundle exec rake spec
  38. 38. Testing your module # spec/classes/init_spec.rb require 'spec_helper' describe 'collectd' do let :facts do {:osfamily => 'RedHat'} end it { should contain_package('collectd').with( :ensure => 'installed' )} it { should contain_service('collectd').with( :ensure => 'running' )} # ...
  39. 39. Testing your module ● Acceptance testing: beaker-rspec ○ github.com/puppetlabs/beaker ○ youtu.be/jEJmUQOlaDg $ bundle exec rspec spec/acceptance
  40. 40. Testing your module # spec/acceptance/class_spec.rb require 'spec_helper_acceptance' case fact('osfamily') # ... describe 'ssh class' do context 'default parameters' do it 'should work with no errors' do pp = "class { 'ssh': }" apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe service(servicename) do it { should be_running } end # ...
  41. 41. Testing your module ● Linting $ bundle exec rake lint
  42. 42. Maintaining your module Update your code ● fix bugs ● add features ● manage pull requests
  43. 43. Installing modules Search for modules on forge.puppetlabs.com or puppet module search ssh Then install with puppet module install saz/ssh
  44. 44. Where now? Learn more at docs.puppetlabs.com/guides/module_guides/bgtm.html Get help at Ask: ask.puppetlabs.com IRC: #puppet on freenode Mailing list: groups.google.com/group/puppet-users
  45. 45. Thanks! Find me: Colleen Murphy freenode: crinkle github: cmurphy twitter: @pdx_krinkle

×