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

Make it SOLID Software Architecture for System Administrators

Make it SOLID Software Architecture for System Administrators

Gave this talk at the International PHP Conference on October 30th, 2013
Follow me on Twitter: @CodeStars

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.

Ole Michaelis

October 30, 2013
Tweet

More Decks by Ole Michaelis

Other Decks in Technology

Transcript

  1. Ole Michaelis & Sönke Ruempler | Jimdo
    Make it SOLID
    Software Architecture for System Administrators

    View Slide

  2. Ole Michaelis
    “Open Source Rockstar”
    @CodeStars
    github.com/nesQuick
    codestars.eu

    View Slide

  3. Sönke
    Ruempler
    “Chief Trolling Officer”
    @s0enke
    github.com/s0enke
    ruempler.eu

    View Slide

  4. Jimdo

    View Slide

  5. because infrastructure development is
    neither a Jenga game!
    S.O.L.I.D

    View Slide

  6. a little poll!
    http://images.fineartamerica.com/images-medium-large/live-long-mr-spock-tobias-woelki.jpg

    View Slide

  7. View Slide

  8. S O L I D

    View Slide

  9. A
    dev/ops
    story
    Ole
    as
    Junior Admin
    Sönke
    as
    Dr. Software

    View Slide

  10. the basics

    View Slide

  11. software architecture
    VS.
    36 years
    >2000 years

    View Slide

  12. configuration management
    Idempotent
    Declarative
    Convergent
    Abstract

    View Slide

  13. View Slide

  14. 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

    View Slide

  15. 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

    View Slide

  16. 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]
    }
    }

    View Slide

  17. 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!

    View Slide

  18. Would you solder a
    lamp directly to the
    electrical wiring in a
    wall?
    Dependency
    Inversion

    View Slide

  19. View Slide

  20. 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]
    }
    }
    }

    View Slide

  21. Stuff tends to
    get big
    Beware of god classes!

    View Slide

  22. 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'] }
    }

    View Slide

  23. View Slide

  24. ?

    View Slide

  25. View Slide

  26. rspec-puppet
    test-kitchen

    View Slide

  27. View Slide

  28. 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
    ?

    View Slide

  29. 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 }
    }

    View Slide

  30. Just because you can,
    doesn’t mean you
    should!
    Single
    Responsibility

    View Slide

  31. 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

    View Slide

  32. View Slide

  33. “programs … are changed by adding new
    code, rather than by changing existing
    code”
    Open Close
    Principle

    View Slide

  34. View Slide

  35. 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
    }

    View Slide

  36. View Slide

  37. View Slide

  38. 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!

    View Slide

  39. >

    View Slide

  40. View Slide

  41. ?
    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]
    }
    }
    }

    View Slide

  42. Don’t call us,
    we call you!
    Hollywood
    Principle

    View Slide

  43. 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.

    View Slide

  44. 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.

    View Slide

  45. 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.

    View Slide

  46. View Slide

  47. 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'
    }
    }
    ?

    View Slide

  48. define php5::specialconfig(
    $ensure = present,
    $sapi,
    $module,
    $key,
    $value,
    $section = undef,
    $path = '/etc/php5/%s/conf.d/%s.ini'
    ) {
    ini_setting { $title:
    ensure => present,
    path => sprintf($path, $sapi, $module),
    section => $section,
    setting => $key,
    value => $value,
    require => Package["php5-${sapi}"]
    }
    }

    View Slide

  49. View Slide

  50. ?

    View Slide

  51. “puppet separate code and data”
    I’m feeling lucky

    View Slide

  52. # /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

    View Slide

  53. 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
    }

    View Slide

  54. hiera
    AWS/Cloudformation LDAP
    DNS
    your selfwritten
    stuff

    View Slide

  55. View Slide

  56. View Slide

  57. View Slide

  58. What about
    I and L
    in SOLID?

    View Slide

  59. You want me to plug
    this in, where?
    Interface
    Segregation

    View Slide

  60. If it looks like a duck,
    quacks like a duck, but
    need batteries - you
    probably have the
    wrong abstraction!
    Liskov
    Substitution

    View Slide

  61. S O L I D

    View Slide

  62. View Slide

  63. Structure your code!
    Node
    Profile
    Profiles
    Role Profile
    Modules
    Resources

    View Slide

  64. Puppet forge
    puppet module registry

    View Slide

  65. Dependency Management
    Librarian Puppet
    Berkshelf (chef)

    View Slide

  66. stdmod
    https://github.com/stdmod

    View Slide

  67. server spec
    http://serverspec.org/

    View Slide

  68. sandboxed
    development
    https://github.com/mlafeldt/skeleton-cookbook
    https://github.com/Jimdo/puppet-skeleton

    View Slide

  69. Thank you!
    Rate this talk!
    https://joind.in/9578

    View Slide

  70. @CodeStars
    [email protected]
    @s0enke
    [email protected]
    Questions?

    View Slide

  71. *I ’m just a blank slide*

    View Slide

  72. 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

    View Slide