Top Banner
Writing and Publishing Puppet Modules Colleen Murphy, Portland State University
39

Portland Puppet User Group June 2014: Writing and publishing puppet modules

Aug 27, 2014

Download

Software

Puppet Labs

"Writing and publishing puppet modules" presented by Colleen Murphy at Portland Puppet User Group June 2014 meeting following June 2014 Triage-a-Thon.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Writing and Publishing Puppet Modules

Colleen Murphy, Portland State University

Page 2: Portland Puppet User Group June 2014: Writing and publishing puppet modules

HelloThis is a beginner’s approach.

Page 3: Portland Puppet User Group June 2014: Writing and publishing puppet modules

HelloPSU’s College of Engineering’s IT department, aka The Computer Action Team (TheCAT),uses puppet to manage a diverse infrastructure.

github.com/pdxcat

Page 4: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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

Page 5: Portland Puppet User Group June 2014: Writing and publishing puppet modules

What should a module do?● Set up a service, such as:

○ ssh○ mysql○ apache○ sudo

● Extend puppet functionality. Examples:○ puppetlabs/stdlib○ puppetlabs/concat

Page 6: Portland Puppet User Group June 2014: Writing and publishing puppet modules

The strategySet up the service… without puppet.

Then iterate.

Page 7: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Layout of a moduleyourmodule/

➔ 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

Page 8: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Layout of a moduleyourmodule/

➔ 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

Page 9: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Layout of a moduleyourmodule/

➔ 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

Page 10: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Starting out$ puppet module generate cmurphy-ssh && mv cmurphy-ssh sshGenerating module at /etc/puppet/modules/cmurphy-sshcmurphy-sshcmurphy-ssh/manifestscmurphy-ssh/manifests/init.ppcmurphy-ssh/speccmurphy-ssh/spec/spec_helper.rbcmurphy-ssh/testscmurphy-ssh/tests/init.ppcmurphy-ssh/READMEcmurphy-ssh/Modulefile

$ mkdir ssh/{files,templates}

Page 11: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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'], }

}

# tests/init.ppinclude ssh

# or

# /etc/puppet/manifests/site.ppnode default { include ssh}

Page 12: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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

# ...

Page 13: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Needs more portability!

No one should have to change your code or your files in order to use your module.

Page 14: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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

# ...

Page 15: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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'], }

# ...

# Applying the classclass { 'ssh': permit_root_login => 'without-password',}

Page 16: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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 classclass { 'ssh': ports => [ 22, 2222 ], options => { 'PermitRootLogin' => 'no', }}

Page 17: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Templating strategies# templates/sshd_config.erb

# Managed by Puppet

<% @ports.each do |port| %>

Port <%= port %>

<% end %>

<% @options.each do |k,v| %>

<%= k %> <%= v %>

<% end %>

Page 18: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Templating strategiesWorking with tricky configuration files● Take advantage of Include conf/* 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'), }}

Page 19: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Beyond templates● puppetlabs/concat

concat { '/etc/motd': }

concat::fragment { 'welcome':

target => '/etc/motd',

content => 'Welcome to Redhat',

order => '01',

}

concat::fragment { 'legal':

# … }

Page 20: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Beyond templates● puppetlabs/inifile

ini_setting { 'puppetdbserver':

ensure => present,

section => 'main',

path => "${puppet_confdir}/puppetdb.conf",

setting => 'server', value => $server,}

ini_setting { 'puppetdbport':

# …}

Page 21: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Beyond Templates● augeas

● domcleal/augeasproviders

augeas { 'sshd_config_permit_root_login': context => '/files/etc/ssh/sshd_config', changes => "set PermitRootLogin $permit_root_login", require => File['/etc/ssh/sshd_config'],}

sshd_config { "PermitRootLogin":

ensure => present,

value => $permit_root_login,

}

Page 22: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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.ppclass ssh (

# ...) { include ssh::params

service { $ssh::params::ssh_svc: ensure => running, enable => true, }

# ...

Page 23: Portland Puppet User Group June 2014: Writing and publishing puppet modules

The Forge

Page 24: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Publishing your moduleModulefilename 'cmurphy-ssh'version '0.0.1'source 'https://github.com/cmurphy/puppet-module-ssh.git'author 'Colleen Murphy'license 'Apache License, Version 2.0'summary 'Puppet module for ssh'description 'Demonstration of parameterized ssh module'project_page 'https://github.com/cmurphy/puppet-module-ssh'

## Add dependencies, if any:# dependency 'username/name', '>= 1.2.0'

Page 25: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Publishing your moduleREADME● docs.puppetlabs.com/puppet/3/reference/READMEtemplate.markdown

license● choosealicense.com

Page 26: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Publishing your moduleChangelog## 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:

...

Page 27: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Publishing your moduleUse semantic versioning! semver.org

Major.Minor.Patch

Page 28: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Publishing your module$ cd ssh/

$ puppet module build .

$ ls pkg/

cmurphy-ssh-0.0.1 cmurphy-ssh-0.0.1.tar.gz

Page 29: Portland Puppet User Group June 2014: Writing and publishing puppet modules

TestingWhy 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

Page 30: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Testing your module● Smoke testing

# puppet apply --noop tests/init.pp

Page 31: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Testing your module● Unit testing: rspec-puppet

○ rspec-puppet.com

$ bundle exec rake spec

Page 32: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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'

)}

# ...

Page 33: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Testing your module● Acceptance testing: beaker-rspec

○ github.com/puppetlabs/beaker○ youtu.be/jEJmUQOlaDg

$ bundle exec rspec spec/acceptance

Page 34: Portland Puppet User Group June 2014: Writing and publishing puppet modules

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': }"

# Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_failures => true)

end

describe service(servicename) do it { should be_running } end

# ...

Page 35: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Testing your module● Linting

$ bundle exec rake lint

Page 36: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Maintaining your moduleUpdate your code● fix bugs● add features● manage pull requests

Page 37: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Installing modulesSearch for modules on forge.puppetlabs.com or puppet module search

Then install with puppet module install

Page 38: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Where now?Learn more at docs.puppetlabs.com/guides/module_guides/bgtm.html

Get help atAsk: ask.puppetlabs.comIRC: #puppet on freenodeMailing list: groups.google.com/group/puppet-users

Page 39: Portland Puppet User Group June 2014: Writing and publishing puppet modules

Thanks!Find me:

Colleen Murphyfreenode: crinklegithub: cmurphy

twitter: @pdx_krinkle