osdc 2014: ole michaelis & sönke rümpler: make it solid - software architecture for system...
DESCRIPTION
Starting with Chef or Puppet as a System Administrator will lead you to a problem where you are not sure what’s the best solution of a problem in terms of software architecture. We will give you a brief overview of general well known and battle tested software patterns, which also applies to infrastructure management code. In addition, we‘ll also show Antipatterns, and best practices.TRANSCRIPT
Ole Michaelis & Sönke Ruempler | Jimdo
Make it SOLIDSoftware Architecture for System Administrators
OSDC 2014
Ole Michaelis“Open Source Rockstar”
@CodeStarsgithub.com/nesQuick
codestars.eu
OSDC 2014
Sönke Ruempler
“Chief Trolling Officer”
@s0enkegithub.com/s0enke
ruempler.eu
OSDC 2014
Jimdo
OSDC 2014
because infrastructure development is neither a Jenga game!
S.O.L.I.D
OSDC 2014
a little poll!
http://images.fineartamerica.com/images-medium-large/live-long-mr-spock-tobias-woelki.jpg
OSDC 2014
OSDC 2014
S O L I D
OSDC 2014
Adev/ops
story
Oleas
Junior Admin
SönkeasDr. Software
OSDC 2014
the basics
OSDC 2014
configuration management
IdempotentDeclarativeConvergent
Abstract
OSDC 2014
software architecture
VS.36 years
>2000 years
OSDC 2014
OSDC 2014
node web-1 {
$role = 'web-app-a'
$has_apache = true;
include php5
}
node web-2 {
$role = 'web-app-b'
$has_fcgi=true
include php5
}
# has both enabled, but needs a special config
node web-3 {
$role = 'web-app-c'
$has_fcgi=true
$has_apache=true
include php5
}
Web App 1
Web App 2
Web App 3
OSDC 2014
class php5 {
if ($::has_fcgi)
package { 'php5-cli' : ensure => installed }
}
if ($::has_apache) {
package { 'php5-apache' : ensure => installed }
}
if ($::role == 'web-app-c')
package { 'php5-web-app-c-special-module' }
file { '/etc/php5/php.ini' :
source => 'puppet:///modules/php5/php.ini-web-app-c'
}
}
}
Global variable!
Out of Context!
No abstraction
OSDC 2014
class php5(
$has_fcgi = false,
$has_apache = false,
$role = undef
) {
if ($has_fcgi)
package { 'php5-cli' : ensure => installed }
}
if ($has_apache) {
package { 'php5-apache' : ensure => installed }
}
if ($role == 'web-app-c') {
package { 'php5-web-app-c-special-module' }
file { '/etc/php5/php.ini' :
source => 'puppet:///modules/php5/php.ini-web-app-c',
require => Package[php-fcgi]
}
}
}
OSDC 2014
node 'web-1' {
$role = 'web-app-a'
$has_apache = true
class { 'php5' :
has_apache => true,
role => 'web-app-a'
}
}
node 'web-2' {
$role = 'web-app-b'
$has_fcgi = true
class { 'php5' :
has_fcgi => true,
role => 'web-app-b'
}
}
Injection!
Injection!
OSDC 2014
Would you solder a lamp directly to the electrical wiring in a
wall?
Dependency Inversion
OSDC 2014
OSDC 2014
class php5(
$has_fcgi = false,
$has_apache = false,
$role = undef
) {
if ($has_fcgi)
package { 'php5-cli' : ensure => installed }
}
if ($has_apache) {
package { 'php5-apache' : ensure => installed }
}
if ($role == 'web-app-c') {
package { 'php5-web-app-c-special-module' }
file { '/etc/php5/php.ini' :
source => 'puppet:///modules/php5/php.ini-web-app-c'
require => Package[php-fcgi]
}
}
}
OSDC 2014
Stuff tends to get big
Beware of god classes!
OSDC 2014
if ($lighttpd) { package { 'php5-cgi': } configdir { '/etc/php5/cgi': require => Package['php5-cgi'] } configdir { '/etc/php5/cgi/conf.d': require => Package['php5-cgi'] } if ($testserver) { configfile { '/etc/php5/cgi/php.ini': sourcename => 'php5/cgi/php.ini-testserver', require => Package['php5-cgi'] } } else { if ($cms ) { configfile { '/etc/php5/cgi/php.ini': sourcename => 'php5/cgi/php.ini-cms', require => Package['php5-cgi'] } } else { if ($mgmt ) { configfile { '/etc/php5/cgi/php.ini': sourcename => 'php5/cgi/php.ini-mgmt', require => Package['php5-cgi'] } } else { if ($lc ) { configfile { '/etc/php5/cgi/php.ini': sourcename => 'php5/cgi/php.ini-lc.jimdo.com', require => Package['php5-cgi'] } } else { configfile { '/etc/php5/cgi/php.ini': sourcename => 'php5/cgi/php.ini', require => Package['php5-cgi'] } } } } } configfile { '/etc/php5/cgi/conf.d/pdo.ini': sourcename => 'php5/cgi/conf.d/pdo.ini', require => Package['php5-cgi'] } }
OSDC 2014
OSDC 2014
?
OSDC 2014
OSDC 2014
rspec-puppet
test-kitchen
OSDC 2014
OSDC 2014
describe :node => 'web-1' do it { should contain_package('php5-fcgi') }end
describe :node => 'web-2' do it { should contain_package('php5-apache2') }end
describe :node => 'web-3' do it { should contain_package('php5-fcgi') } it { should contain_package('php5-apache2') }end
Test php5 class:Install Package
?
OSDC 2014
describe :class => 'php5::fcgi' do it { should contain_package('php5-cli') }end
describe :class => 'php5::apache' do it { should contain_package('php5-apache2') }end
class php5::fgci { package { 'php5-cgi' : ensure => installed }} class php5::apache { package { 'php5-apache' : ensure => installed }}
OSDC 2014
Just because you can, doesn’t mean you
should!
Single Responsibility
OSDC 2014
describe :node => 'web-1' do it { should include_class('php5::fcgi') } it { should contain_package('php5-fcgi') }end describe :node => 'web-2' do it { should include_class('php5::apache') } it { should contain_package('php5-apache2') }end
node web-1 { include php5::apache} node web-2 { include php5::fcgi}
Tests
Code
OSDC 2014
OSDC 2014
“programs […] are changed by adding new code, rather than by changing
existing code”
Open ClosePrinciple
OSDC 2014
OSDC 2014
new requirements...now web app 1 needs a second
node
node web-1 { $role = 'web-app-a' include php5::apache}
node web-1a { $role = 'web-app-a' include php5::apache}
OSDC 2014
OSDC 2014
OSDC 2014
class role::web-app-a { include php5::apache}
node web-1 { include role::web-app-a} node web-1a { include role::web-app-a}
Our new role!
And nodes just include it!
OSDC 2014
>
OSDC 2014
OSDC 2014
?class php5::fcgi($role = undef) {
if ($role == 'web-app-c') {
package { 'php5-web-app-c-special-module' }
file { '/etc/php5/php.ini' :
source =>
'puppet:///modules/php5/php.ini-web-app-c',
require => Package[php-fcgi]
}
}
}
OSDC 2014
Don’t call us,we call you!
Hollywood Principle
OSDC 2014
class role::web-app-c::special-php-stuff { package { 'php5-web-app-c-special-module' } file { '/etc/php5/php.ini' : source => 'puppet:///modules/php5/php.ini-web-app-c' }}
1. Split out the special case into its own class.
OSDC 2014
class php5::fcgi($include_after_package_install = undef) { package { 'php5-fcgi' : ensure => installed } if ($include_after_package_install) include $include_after_package_install Package['php5-fcgi'] -> Class[$include_after_package_install] }}
2. Make the special case pluggable and reusable.
2a. And name it abstract.
OSDC 2014
class role::web-app-c { include php5::apache class { 'php5::fcgi' : include_after_package_install => 'profile::web-app-c::special-php-stuff' }}
3. Pass the special case as dependency in our web-app-c.
OSDC 2014
OSDC 2014
class profile::web-app-c::special-php-stuff { package { 'php5-web-app-c-special-module' } file { '/etc/php5/php.ini' : source => 'puppet:///modules/php5/php.ini-web-app-c' }} ?
OSDC 2014
define php5::specialconfig( $ensure = present, $sapi, $module, $key, $value, $section = undef, $path = '/etc/php5/%s/conf.d/%s.ini') { ini_setting { $title: ensure => $ensure, path => sprintf($path, $sapi, $module), section => $section, setting => $key, value => $value, require => Package["php5-${sapi}"] }}
OSDC 2014
OSDC 2014
?
OSDC 2014
“puppet separate code and data”
I’m feeling lucky
OSDC 2014
# /etc/puppet/hieradata/web1.yaml---classes:- profile::web-app-a # /etc/puppet/hieradata/web1a.yaml---classes:- profile::web-app-a # /etc/puppet/hieradata/web2.yaml---classes:- profile::web-app-c # /etc/puppet/hieradata/web3.yaml---classes:- profile::web-app-c
puppet-hiera
example in YAML
OSDC 2014
node default { hiera_include('classes')}
node web-1 { include role::web-app-a} node web-1a { include role::web-app-a}
node web-2 { include role::web-app-b}
node web-3 { include role::web-app-c}
OSDC 2014
hiera
AWS/Cloudformation LDAP
DNSyour selfwritten stuff
OSDC 2014
OSDC 2014
OSDC 2014
OSDC 2014
What about I and L
in SOLID?
OSDC 2014
You want me to plug this in, where?
Interface Segregation
OSDC 2014
If it looks like a duck, quacks like a duck, but
need batteries - you probably have the wrong abstraction!
Liskov Substitution
OSDC 2014
S O L I D
OSDC 2014
OSDC 2014
Structure your code!Node
ProfileProfilesRole ProfileModules
Resources
OSDC 2014
Puppet forge
puppet module registry
OSDC 2014
Librarian Puppetr10k
Berkshelf (chef)
OSDC 2014
sandboxeddevelopment
https://github.com/mlafeldt/skeleton-cookbookhttps://github.com/Jimdo/puppet-skeleton
OSDC 2014
server spechttp://serverspec.org/
beaker(puppet)
https://github.com/puppetlabs/beaker
OSDC 2014
Thank you!
OSDC 2014
Questions?
OSDC 2014
*I ’m just a blank slide*
OSDC 2014
Sources• http://www.slideshare.net/PuppetLabs/garethrushgrove-puppetconf• http://www.slideshare.net/PuppetLabs/alessandro-franceschi-new• https://github.com/jedi4ever/stop-the-fork• http://lostechies.com/derickbailey/2009/02/11/solid-development-principles-in-motivational-
pictures/• https://speakerdeck.com/jfryman/refactoring-puppet• http://www.clker.com/cliparts/e/2/a/d/1206574733930851359Ryan_Taylor_Green_Tick.svg.med.
png• http://www.craigdunn.org/2012/05/239/• http://cdn.slashgear.com/wp-content/uploads/2012/10/google-datacenter-tech-13.jpg• http://deviq.com/Media/Default/Article/Dont-Call-Us-Well-Call-You-Jun-2013.png• http://www.timeshighereducation.co.uk/Pictures/web/g/q/g/copy_paste_keyboard_button_450.jpg• http://sanremo.com.au/wp-content/uploads/2013/05/lasagna.jpg• http://4.bp.blogspot.
com/_9kQQgQD35rY/SaV5p8YBGhI/AAAAAAAAAkg/HOvlhIo7yGI/s400/06_Red_Green_Refactor.JPG
• http://www.thelolshop.com/wp-content/uploads/2012/11/20121126-101937.jpg•