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

Cleaning Up Chef With Ingredients

Cleaning Up Chef With Ingredients

A whirlwind tour of Chef followed by a brief introduction to Ingredients.

David P. Kleinschmidt

February 12, 2013
Tweet

Other Decks in Programming

Transcript

  1. Chef is… • a centralized system for managing the configuration

    of all the servers in an organization • not restricted to managing Ruby services • able to manage Linux and Windows servers • maintained by Opscode, Inc. http://opscode.com What is Chef?
  2. How do you update the SSL certificate on your web

    server? $ sftp cert.pem admin@www:apache.pem $ ssh admin@www $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit Okay, but… Why use Chef?
  3. Why use Chef? How do you update the SSL certificates

    on eight web servers? Yowza. $ sftp cert.pem admin@www1:apache.pem $ ssh admin@www1 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit $ sftp cert.pem admin@www4:apache.pem $ ssh admin@www4 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit $ sftp cert.pem admin@www7:apache.pem $ ssh admin@www7 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit $ sftp cert.pem admin@www2:apache.pem $ ssh admin@www2 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit $ sftp cert.pem admin@www5:apache.pem $ ssh admin@www5 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit $ sftp cert.pem admin@www8:apache.pem $ ssh admin@www8 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit $ sftp cert.pem admin@www3:apache.pem $ ssh admin@www3 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit $ sftp cert.pem admin@www6:apache.pem $ ssh admin@www6 $ sudo cp apache.pem /etc/ssl $ sudo invoke-rc.d apache restart $ exit
  4. How do you update the SSL certificates on eight web

    servers? • Save the new certificate to Chef Server • As your web servers check in, they will find that the certificate has changed • They will automatically put the new certificate where it belongs and restart Apache Why use Chef?
  5. There are lots of other good reasons, too: • Enforces

    consistency between nodes in a cluster • Allows you to quickly add nodes to a cluster • Allows you to create an exact duplicate of your environment Why use Chef?
  6. Every server, or node, has a run list that says

    which services it should provide. Every node has attributes describing how its services should be configured. How does Chef know what to do?
  7. How does Chef know what to do? Recipes pass the

    nodes’ attributes through templates to the configuration files the services expect. A collection of attributes, templates, and recipes is called a cookbook. Typically, you will use one cookbook per service.
  8. Your options are limited: • Fork and customize a community

    cookbook http://community.opscode.com/cookbooks • …or start from scratch. Where do I get cookbooks?
  9. Opscode’s docs are long on what you can do, but

    short on what you should do. So… learn from example? Hmm… How do I cookbook?
  10. WAT R U DOIN default[‘postgresql’][‘config’][‘data_directory’] = “/var/lib/postgresql/#{node[‘postgresql’][‘version’]}/main” default[‘postgresql’][‘config’][‘hba_file’] = “/etc/postgresql/#{node[‘postgresql’][‘version’]}/main/pg_hba.conf”

    default[‘postgresql’][‘config’][‘ident_file’] = “/etc/postgresql/#{node[‘postgresql’][‘version’]}/main/pg_ident” default[‘postgresql’][‘config’][‘external_pid_file’] = “/var/run/postgresql/#{node[‘postgresql’][‘version’]}-main.pid” default[‘postgresql’][‘config’][‘listen_addresses’] = ‘localhost’ default[‘postgresql’][‘config’][‘port’] = 5432 default[‘postgresql’][‘config’][‘max_connections’] = 100 default[‘postgresql’][‘config’][‘unix_socket_directory’] = ‘/var/run/postgresql’ default[‘postgresql’][‘config’][‘shared_buffers’] = ‘24MB’ default[‘postgresql’][‘config’][‘max_fsm_pages’] = 153600 \ if node[‘postgresql’][‘version’].to_f < 8.4 default[‘postgresql’][‘config’][‘log_line_prefix’] = ‘%t ‘ default[‘postgresql’][‘config’][‘datestyle’] = ‘iso, mdy’ default[‘postgresql’][‘config’][‘default_text_search_config’] = ‘pg_catalog.english’ default[‘postgresql’][‘config’][‘ssl’] = true
  11. CHEF case node[‘platform_family’] when ‘debian’ default[‘postgresql’][‘config’][‘data_directory’] = “/var/lib/postgresql/#{node[‘postgresql’][‘version’]}/main” default[‘postgresql’][‘config’][‘hba_file’] =

    “/etc/postgresql/#{node[‘postgresql’][‘version’]}/main/pg_hb” default[‘postgresql’][‘config’][‘ident_file’] = “/etc/postgresql/#{node[‘postgresql’][‘version’]}/main/pg_id” default[‘postgresql’][‘config’][‘external_pid_file’] = “/var/run/postgresql/#{node[‘postgresql’][‘version’]}-main” default[‘postgresql’][‘config’][‘listen_addresses’] = ‘localhost’ default[‘postgresql’][‘config’][‘port’] = 5432 default[‘postgresql’][‘config’][‘max_connections’] = 100 default[‘postgresql’][‘config’][‘unix_socket_directory’] = ‘/var/run/postgresql’ default[‘postgresql’][‘config’][‘shared_buffers’] = ‘24MB’ default[‘postgresql’][‘config’][‘max_fsm_pages’] = 153600 \ if node[‘postgresql’][‘version’].to_f < 8.4 default[‘postgresql’][‘config’][‘log_line_prefix’] = ‘%t ‘ default[‘postgresql’][‘config’][‘datestyle’] = ‘iso, mdy’ default[‘postgresql’][‘config’][‘default_text_search_config’] = ‘pg_catalog.english’ default[‘postgresql’][‘config’][‘ssl’] = true when ‘rhel’, ‘fedora’, ‘suse’ default[‘postgresql’][‘config’][‘listen_addresses’] = ‘localhost’ default[‘postgresql’][‘config’][‘max_connections’] = 100 default[‘postgresql’][‘config’][‘shared_buffers’] = ‘32MB’ default[‘postgresql’][‘config’][‘logging_collector’] = true default[‘postgresql’][‘config’][‘log_directory’] = ‘pg_log’ default[‘postgresql’][‘config’][‘log_filename’] = ‘postgresql-%a.log’ default[‘postgresql’][‘config’][‘log_truncate_on_rotation’] = true default[‘postgresql’][‘config’][‘log_rotation_age’] = ‘1d’ default[‘postgresql’][‘config’][‘log_rotation_size’] = 0 default[‘postgresql’][‘config’][‘datestyle’] = ‘iso, mdy’ default[‘postgresql’][‘config’][‘lc_messages’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘lc_monetary’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘lc_numeric’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘lc_time’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘default_text_search_config’] = ‘pg_catalog.english’ end
  12. STAHP # # Cookbook Name:: postgresql # Attributes:: postgresql #

    # Copyright 2008-2009, Opscode, Inc. # # Licensed under the Apache License, Version 2.0 (the “License”); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an “AS IS” BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # case node[‘platform’] when “debian” case when node[‘platform_version’].to_f < 6.0 # All 5.X default[‘postgresql’][‘version’] = “8.3” when node[‘platform_version’].to_f < 7.0 # All 6.X default[‘postgresql’][‘version’] = “8.4” else default[‘postgresql’][‘version’] = “9.1” end default[‘postgresql’][‘dir’] = “/etc/ postgresql/#{node[‘postgresql’][‘version’]}/main” case when node[‘platform_version’].to_f < 6.0 # All 5.X default[‘postgresql’][‘server’][‘service_name’] = “postgresql-#{node[‘postgresql’][‘version’]}” else default[‘postgresql’][‘server’][‘service_name’] = “postgresql” end default[‘postgresql’][‘client’][‘packages’] = %w{postgresql-client libpq-dev} default[‘postgresql’][‘server’][‘packages’] = %w{postgresql} default[‘postgresql’][‘contrib’] [‘packages’] = %w{postgresql-contrib} when “ubuntu” case when node[‘platform_version’].to_f <= 9.04 default[‘postgresql’][‘version’] = “8.3” when node[‘platform_version’].to_f <= 11.04 default[‘postgresql’][‘version’] = “8.4” else default[‘postgresql’][‘version’] = “9.1” end default[‘postgresql’][‘dir’] = “/etc/ postgresql/#{node[‘postgresql’][‘version’]}/main” case when node[‘platform_version’].to_f <= 10.04 default[‘postgresql’][‘server’][‘service_name’] = “postgresql-#{node[‘postgresql’][‘version’]}” else default[‘postgresql’][‘server’][‘service_name’] = “postgresql” end default[‘postgresql’][‘client’][‘packages’] = %w{postgresql-client libpq-dev} default[‘postgresql’][‘server’][‘packages’] = %w{postgresql} default[‘postgresql’][‘contrib’] [‘packages’] = %w{postgresql-contrib} when “fedora” if node[‘platform_version’].to_f <= 12 default[‘postgresql’][‘version’] = “8.3” else default[‘postgresql’][‘version’] = “8.4” end default[‘postgresql’][‘dir’] = “/var/lib/pgsql/data” default[‘postgresql’][‘client’][‘packages’] = %w{postgresql-devel} default[‘postgresql’][‘server’][‘packages’] = %w{postgresql-server} default[‘postgresql’][‘contrib’] [‘packages’] = %w{postgresql-contrib} default[‘postgresql’][‘server’][‘service_name’] = “postgresql” when “amazon” default[‘postgresql’][‘version’] = “8.4” default[‘postgresql’][‘dir’] = “/var/lib/pgsql/data” default[‘postgresql’][‘client’][‘packages’] = %w{postgresql-devel} default[‘postgresql’][‘server’][‘packages’] = %w{postgresql-server} default[‘postgresql’][‘contrib’] [‘packages’] = %w{postgresql-contrib} default[‘postgresql’][‘server’][‘service_name’] = “postgresql” when “redhat”, “centos”, “scientific”, “oracle” default[‘postgresql’][‘version’] = “8.4” default[‘postgresql’][‘dir’] = “/var/lib/pgsql/data” if node[‘platform_version’].to_f >= 6.0 default[‘postgresql’][‘client’] [‘packages’] = %w{postgresql-devel} default[‘postgresql’][‘server’] [‘packages’] = %w{postgresql-server} default[‘postgresql’][‘contrib’] [‘packages’] = %w{postgresql-contrib} else default[‘postgresql’][‘client’][‘packages’] = [“postgresql#{node[‘postgresql’][‘version’].split(‘.’).join}-devel”] default[‘postgresql’][‘server’][‘packages’] = [“postgresql#{node[‘postgresql’][‘version’].split(‘.’).join}-server”] default[‘postgresql’][‘contrib’] [‘packages’] = [“postgresql#{node[‘postgresql’] [‘version’].split(‘.’).join}-contrib”] end default[‘postgresql’][‘server’][‘service_name’] = “postgresql” when “suse” if node[‘platform_version’].to_f <= 11.1 default[‘postgresql’][‘version’] = “8.3” else default[‘postgresql’][‘version’] = “9.0” end default[‘postgresql’][‘dir’] = “/var/lib/pgsql/data” default[‘postgresql’][‘client’][‘packages’] = %w{postgresql-devel} default[‘postgresql’][‘server’][‘packages’] = %w{postgresql-server} default[‘postgresql’][‘contrib’] [‘packages’] = %w{postgresql-contrib} default[‘postgresql’][‘server’][‘service_name’] = “postgresql” else default[‘postgresql’][‘version’] = “8.4” default[‘postgresql’][‘dir’] = “/etc/ postgresql/#{node[‘postgresql’][‘version’]}/main” default[‘postgresql’][‘client’][‘packages’] = [“postgresql”] default[‘postgresql’][‘server’][‘packages’] = [“postgresql”] default[‘postgresql’][‘contrib’][‘packages’] = [“postgresql”] default[‘postgresql’][‘server’][‘service_name’] = “postgresql” end # These defaults have disparity between which postgresql configuration # settings are used because they were extracted from the original # configuration files that are now removed in favor of dynamic # generation. # # While the configuration ends up being the same as the default # in previous versions of the cookbook, the content of the rendered # template will change, and this will result in service notification # if you upgrade the cookbook on existing systems. # # The ssl config attribute is generated in the recipe to avoid awkward # merge/precedence order during the Chef run. case node[‘platform_family’] when ‘debian’ default[‘postgresql’][‘config’][‘data_directory’] = “/var/ lib/postgresql/#{node[‘postgresql’][‘version’]}/main” default[‘postgresql’][‘config’][‘hba_file’] = “/etc/ postgresql/#{node[‘postgresql’][‘version’]}/main/pg_hba.conf” default[‘postgresql’][‘config’][‘ident_file’] = “/etc/ postgresql/#{node[‘postgresql’][‘version’]}/main/pg_ident.conf” default[‘postgresql’][‘config’][‘external_pid_file’] = “/var/ run/postgresql/#{node[‘postgresql’][‘version’]}-main.pid” default[‘postgresql’][‘config’][‘listen_addresses’] = ‘localhost’ default[‘postgresql’][‘config’][‘port’] = 5432 default[‘postgresql’][‘config’][‘max_connections’] = 100 default[‘postgresql’][‘config’][‘unix_socket_ directory’] = ‘/var/run/postgresql’ default[‘postgresql’][‘config’][‘shared_buffers’] = ‘24MB’ default[‘postgresql’][‘config’][‘max_fsm_pages’] = 153600 if node[‘postgresql’][‘version’].to_f < 8.4 default[‘postgresql’][‘config’][‘log_line_prefix’] = ‘%t ‘ default[‘postgresql’][‘config’][‘datestyle’] = ‘iso, mdy’ default[‘postgresql’][‘config’][‘default_text_ search_config’] = ‘pg_catalog.english’ default[‘postgresql’][‘config’][‘ssl’] = true when ‘rhel’, ‘fedora’, ‘suse’ default[‘postgresql’][‘config’][‘listen_addresses’] = ‘localhost’ default[‘postgresql’][‘config’][‘max_connections’] = 100 default[‘postgresql’][‘config’][‘shared_buffers’] = ‘32MB’ default[‘postgresql’][‘config’][‘logging_collector’] = true default[‘postgresql’][‘config’][‘log_directory’] = ‘pg_log’ default[‘postgresql’][‘config’][‘log_ filename’] = ‘postgresql-%a.log’ default[‘postgresql’][‘config’][‘log_truncate_on_rotation’] = true default[‘postgresql’][‘config’][‘log_rotation_age’] = ‘1d’ default[‘postgresql’][‘config’][‘log_rotation_size’] = 0 default[‘postgresql’][‘config’][‘datestyle’] = ‘iso, mdy’ default[‘postgresql’][‘config’][‘lc_messages’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘lc_monetary’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘lc_numeric’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘lc_time’] = ‘en_US.UTF-8’ default[‘postgresql’][‘config’][‘default_text_ search_config’] = ‘pg_catalog.english’ end default[‘postgresql’][‘pg_hba’] = [ {:type => ‘local’, :db => ‘all’, :user => ‘postgres’, :addr => nil, :method => ‘ident’}, {:type => ‘local’, :db => ‘all’, :user => ‘all’, :addr => nil, :method => ‘ident’}, {:type => ‘host’, :db => ‘all’, :user => ‘all’, :addr => ‘127.0.0.1/32’, :method => ‘md5’}, {:type => ‘host’, :db => ‘all’, :user => ‘all’, :addr => ‘::1/128’, :method => ‘md5’} ] default[‘postgresql’][‘password’] = Hash.new default[‘postgresql’][‘enable_pitti_ppa’] = false default[‘postgresql’][‘enable_pgdg_yum’] = false # The PostgreSQL RPM Building Project built repository RPMs for easy # access to the PGDG yum repositories. Links to RPMs for installation # on the supported version/platform combinations are listed at # http://yum.postgresql.org/repopackages.php, and the links for # PostgreSQL 8.4, 9.0, 9.1 and 9.2 (from 2013- 01-15) are captured below. # # The correct RPM for installing /etc/yum.repos.d is based on: # * the attribute configuring the desired Postgres Software: # node[‘postgresql’][‘version’] e.g., “9.1” # * the chef ohai description of the target Operating System: # node[‘platform’] e.g., “centos” # node[‘platform_version’] e.g., “5.7”, truncated as “5” # node[‘kernel’][‘machine’] e.g., “i386” or “x86_64” default[‘postgresql’][‘pgdg’][‘repo_rpm_url’] = { “9.2” => { “centos” => { “6” => { “i386” => “http://yum.postgresql.org/9.2/redhat/ rhel-6-i386/pgdg-centos92-9.2-6.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/ redhat/rhel-6-x86_64/pgdg-centos92-9.2-6.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.2/redhat/ rhel-5-i386/pgdg-centos92-9.2-6.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/ redhat/rhel-5-x86_64/pgdg-centos92-9.2-6.noarch.rpm” } }, “redhat” => { “6” => { “i386” => “http://yum.postgresql.org/9.2/redhat/ rhel-6-i386/pgdg-redhat92-9.2-7.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/ redhat/rhel-6-x86_64/pgdg-redhat92-9.2-7.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.2/redhat/ rhel-5-i386/pgdg-redhat92-9.2-7.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/ redhat/rhel-5-x86_64/pgdg-redhat92-9.2-7.noarch.rpm” } }, “scientific” => { “6” => { “i386” => “http://yum.postgresql.org/9.2/ redhat/rhel-6-i386/pgdg-sl92-9.2-8.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/ redhat/rhel-6-x86_64/pgdg-sl92-9.2-8.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.2/ redhat/rhel-5-i386/pgdg-sl92-9.2-8.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/ redhat/rhel-5-x86_64/pgdg-sl92-9.2-8.noarch.rpm” } }, “fedora” => { “17” => { “x86_64” => “http://yum.postgresql.org/9.2/fedora/ fedora-17-x86_64/pgdg-fedora92-9.2-5.noarch.rpm” }, “16” => { “i386” => “http://yum.postgresql.org/9.2/fedora/ fedora-16-i386/pgdg-fedora92-9.2-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/fedora/ fedora-16-x86_64/pgdg-fedora92-9.2-5.noarch.rpm” }, “15” => { “i386” => “http://yum.postgresql.org/9.2/fedora/ fedora-15-i386/pgdg-fedora92-9.2-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.2/fedora/ fedora-15-x86_64/pgdg-fedora92-9.2-5.noarch.rpm” } } }, “9.1” => { “centos” => { “6” => { “i386” => “http://yum.postgresql.org/9.1/redhat/ rhel-6-i386/pgdg-centos91-9.1-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-5-x86_64/pgdg-centos91-9.1-4.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.1/redhat/ rhel-5-i386/pgdg-centos91-9.1-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-5-x86_64/pgdg-centos91-9.1-4.noarch.rpm” }, “4” => { “i386” => “http://yum.postgresql.org/9.1/redhat/ rhel-4-i386/pgdg-centos91-9.1-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-4-x86_64/pgdg-centos91-9.1-4.noarch.rpm” } }, “redhat” => { “6” => { “i386” => “http://yum.postgresql.org/9.1/redhat/ rhel-6-i386/pgdg-redhat91-9.1-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-6-x86_64/pgdg-redhat91-9.1-5.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.1/redhat/ rhel-5-i386/pgdg-redhat91-9.1-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-5-x86_64/pgdg-redhat91-9.1-5.noarch.rpm” }, “4” => { “i386” => “http://yum.postgresql.org/9.1/ redhat/rhel-4-i386/pgdg-redhat-9.1-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-4-x86_64/pgdg-redhat-9.1-4.noarch.rpm” } }, “scientific” => { “6” => { “i386” => “http://yum.postgresql.org/9.1/ redhat/rhel-6-i386/pgdg-sl91-9.1-6.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-6-x86_64/pgdg-sl91-9.1-6.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.1/ redhat/rhel-5-i386/pgdg-sl91-9.1-6.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/ redhat/rhel-5-x86_64/pgdg-sl91-9.1-6.noarch.rpm” } }, “fedora” => { “16” => { “i386” => “http://yum.postgresql.org/9.1/fedora/ fedora-16-i386/pgdg-fedora91-9.1-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/fedora/ fedora-16-x86_64/pgdg-fedora91-9.1-4.noarch.rpm” }, “15” => { “i386” => “http://yum.postgresql.org/9.1/fedora/ fedora-15-i386/pgdg-fedora91-9.1-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/fedora/ fedora-15-x86_64/pgdg-fedora91-9.1-4.noarch.rpm” }, “14” => { “i386” => “http://yum.postgresql.org/9.1/fedora/ fedora-14-i386/pgdg-fedora91-9.1-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.1/fedora/ fedora-14-x86_64/pgdg-fedora-9.1-2.noarch.rpm” } } }, “9.0” => { “centos” => { “6” => { “i386” => “http://yum.postgresql.org/9.0/redhat/ rhel-6-i386/pgdg-centos90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-6-x86_64/pgdg-centos90-9.0-5.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.0/redhat/ rhel-5-i386/pgdg-centos90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-5-x86_64/pgdg-centos90-9.0-5.noarch.rpm” }, “4” => { “i386” => “http://yum.postgresql.org/9.0/redhat/ rhel-4-i386/pgdg-centos90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-4-x86_64/pgdg-centos90-9.0-5.noarch.rpm” } }, “redhat” => { “6” => { “i386” => “http://yum.postgresql.org/9.0/redhat/ rhel-6-i386/pgdg-redhat90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-6-x86_64/pgdg-redhat90-9.0-5.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.0/redhat/ rhel-5-i386/pgdg-redhat90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-5-x86_64/pgdg-redhat90-9.0-5.noarch.rpm” }, “4” => { “i386” => “http://yum.postgresql.org/9.0/redhat/ rhel-4-i386/pgdg-redhat90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-4-x86_64/pgdg-redhat90-9.0-5.noarch.rpm” } }, “scientific” => { “6” => { “i386” => “http://yum.postgresql.org/9.0/ redhat/rhel-6-i386/pgdg-sl90-9.0-6.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-6-x86_64/pgdg-sl90-9.0-6.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/9.0/ redhat/rhel-5-i386/pgdg-sl90-9.0-6.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/ redhat/rhel-5-x86_64/pgdg-sl90-9.0-6.noarch.rpm” } }, “fedora” => { “15” => { “i386” => “http://yum.postgresql.org/9.0/fedora/ fedora-15-i386/pgdg-fedora90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/fedora/ fedora-15-x86_64/pgdg-fedora90-9.0-5.noarch.rpm” }, “14” => { “i386” => “http://yum.postgresql.org/9.0/fedora/ fedora-14-i386/pgdg-fedora90-9.0-5.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/9.0/fedora/ fedora-14-x86_64/pgdg-fedora90-9.0-5.noarch.rpm” } } }, “8.4” => { “centos” => { “6” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-6-i386/pgdg-centos-8.4-3.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-6-x86_64/pgdg-centos-8.4-3.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-5-i386/pgdg-centos-8.4-3.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-5-x86_64/pgdg-centos-8.4-3.noarch.rpm” }, “4” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-4-i386/pgdg-centos-8.4-3.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-4-x86_64/pgdg-centos-8.4-3.noarch.rpm” } }, “redhat” => { “6” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-6-i386/pgdg-redhat-8.4-3.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-6-x86_64/pgdg-redhat-8.4-3.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-5-i386/pgdg-redhat-8.4-3.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-5-x86_64/pgdg-redhat-8.4-3.noarch.rpm” }, “4” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-4-i386/pgdg-redhat-8.4-3.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-4-x86_64/pgdg-redhat-8.4-3.noarch.rpm” } }, “scientific” => { “6” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-6-i386/pgdg-sl84-8.4-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-6-x86_64/pgdg-sl84-8.4-4.noarch.rpm” }, “5” => { “i386” => “http://yum.postgresql.org/8.4/ redhat/rhel-5-i386/pgdg-sl-8.4-4.noarch.rpm”, “x86_64” => “http://yum.postgresql.org/8.4/ redhat/rhel-5-x86_64/pgdg-sl-8.4-4.noarch.rpm” } }, “fedora” => { “14” => { “i386” => “http://yum.postgresql. org/8.4/fedora/fedora-14-i386/”, “x86_64” => “http://yum.postgresql. org/8.4/fedora/fedora-14-x86_64/” }, “13” => { “i386” => “http://yum.postgresql. org/8.4/fedora/fedora-13-i386/”, “x86_64” => “http://yum.postgresql. org/8.4/fedora/fedora-13-x86_64/” }, “12” => { “i386” => “http://yum.postgresql. org/8.4/fedora/fedora-12-i386/”, “x86_64” => “http://yum.postgresql. org/8.4/fedora/fedora-12-x86_64/” }, “8” => { “i386” => “http://yum.postgresql. org/8.4/fedora/fedora-8-i386/”, “x86_64” => “http://yum.postgresql. org/8.4/fedora/fedora-8-x86_64/” }, “7” => { “i386” => “http://yum.postgresql. org/8.4/fedora/fedora-7-i386/”, “x86_64” => “http://yum.postgresql. org/8.4/fedora/fedora-7-x86_64/” } } }, };
  13. postgresql/attributes/default.rb: • 412 lines long • 39 attributes set •

    average of ~10½ lines per attribute The code is dense, but the information is sparse Well, that escalated quickly…
  14. Did we just trade a system administration annoyance for a

    software maintenance nightmare? Is it worthwhile to fix? Can it be fixed? How do we fix it? What happened here?
  15. Attributes are the data that describe how a service is

    configured. Templates define how configuration parameters are presented to the service. Recipes shuttle data from the attributes to the templates. What is a cookbook again?
  16. Models are the data that describe how an application is

    put together. Views define how information is presented to the user. Controllers shuttle data from the models to the views. This looks familiar…
  17. The nested hash analogy provides very flexible data storage, but

    its usefulness is limited without any domain knowledge. This pushes “model” decisions out into other parts of the cookbook. This is made worse by the quirks of the attribute storage implementation. Chef attributes aren’t smart enough
  18. Ingredients is: • a DSL for defining attributes in a

    maintainable fashion • a smart API for accessing attributes • available at http://github.com/zobar/ingredients Ingredients to the rescue
  19. Ingredients.for_cookbook :postgresql do namespace :config do attribute :version, default: ‘8.4’

    attribute :data_directory, default: ‘/var/lib/postgresql/#{version}/main’ end end Let’s try this again.
  20. Ingredients.for_cookbook :postgresql do namespace :config do attribute :version, default: ‘8.4’

    attribute :data_directory, default: “/var/lib/postgresql/#{version}/main” attribute :hba_file, default: etc_file(‘hba.conf’) attribute :ident_file, default: etc_file(‘pg_ident.conf’) attribute :external_pid_file, default: var_run_file(“#{version}-main.pid”) attribute :listen_addresses, default: [‘localhost’] attribute :port, default: 5432 attribute :max_connections, default: 100 attribute :unix_socket_directory, default: var_run_file attribute :shared_buffers, default: ‘24MB’ attribute :log_line_prefix, default: ‘%t ’ attribute :datestyle, default: ‘iso, mdy’ attribute :default_text_search_config, default: ‘pg_catalog.english’ attribute :ssl, default: true def etc_file(file) “/etc/postgresql/#{version}/main/#{file}” end def var_run_file(file=nil) “/var/run/postgresql/#{file}” end end end …and then?
  21. # # Copyright 2012, David P. Kleinschmidt # # Permission

    is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # Ingredients.for_cookbook :postgresql do data_bag_item ‘services’, ‘postgresql’ named_collection :versions, default: ‘8.4’ do named_collection :clusters, default: ‘main’ do attribute :data_directory, default: proc {“/var/lib/postgresql/#{parent.name}/#{name}”} attribute :group, default: ‘postgres’ attribute :listen_addresses, default: [‘localhost’] attribute :locale, default: ‘en_US.utf8’ attribute :logfile, default: proc {“/var/log/ postgresql/postgresql-#{parent.name}-#{name}.log”} attribute :port, default: 5432 attribute :unix_socket_directory, default: ‘/var/run/postgresql’ attribute :user, default: ‘postgres’ data_bag_attribute :root_certificate data_bag_attribute :root_crl data_bag_attribute :server_certificate data_bag_attribute :server_key def create_command options = { datadir: :data_directory, group: :group, locale: :locale, logfile: :logfile, port: :port, socketdir: :unix_socket_directory, user: :user }.collect{|flag, key| “--#{flag} ‘#{config[key]}’”}.join(‘ ‘) “pg_createcluster #{options} --start #{parent.name} #{name}” end named_collection :databases do attribute :configuration, default: {} attribute :connection_limit attribute :encoding attribute :locale attribute :owner attribute :template def create_command options = [“CREATE DATABASE #{name}”] unless connection_limit.nil? options << “CONNECTION LIMIT #{connection_limit}” end options << “ENCODING ‘#{encoding}’” unless encoding.nil? unless locale.nil? options << “LC_COLLATE ‘#{locale}’” options << “LC_CTYPE ‘#{locale}’” end options << “OWNER #{owner}” unless owner.nil? options << “TEMPLATE #{template}” unless template.nil? commands = [“#{options.join(‘ ‘)};”] configuration.each do |parameter, value| commands << “ALTER DATABASE #{name} SET #{parameter} = #{value};” end commands.join “\n” end end ordered_collection :hba do attribute :cidr_address attribute :databases, default: [‘all’] attribute :method, default: ‘md5’ attribute :types, default: [‘host’] attribute :users, default: [‘all’] end search_collection :roles, as: :role, sources: [:people, :services] do attribute :admin, default: [] attribute :connection_limit attribute :createdb, default: false attribute :createrole, default: false attribute :inherit, default: true attribute :in_role, default: [] attribute :login, default: false attribute :password attribute :role, default: [] attribute :superuser, default: false attribute :valid_until def create_command options = [“CREATE ROLE #{name}”] options << “ADMIN #{admin.join(‘, ‘)}” unless admin.empty? unless connection_limit.nil? options << “CONNECTION LIMIT #{connection_limit}” end options << ‘CREATEDB’ if createdb options << ‘CREATEROLE’ if createrole options << “IN ROLE #{in_role.join(‘, ‘)}” unless in_role.empty? options << ‘LOGIN’ if login options << ‘NOINHERIT’ unless inherit options << “PASSWORD ‘#{password}’” unless password.nil? options << “ROLE #{role.join(‘, ‘)}” unless role.empty? options << ‘SUPERUSER’ if superuser options << “VALID UNTIL #{valid_until}” unless valid_until.nil? “#{options.join(‘ ‘)};” end end end end end …and then??
  22. How did we do? postgresql-ingredients/attributes/default.rb: • 127 lines long •

    36 attributes set • average of ~3½ lines per attribute (including helper methods) • plus it has more features than the community cookbook
  23. cluster.roles.each do |id, role| # # CREATE ROLE for every

    user. # postgresql_ingredients_script “create_role:#{version}:#{cluster}:#{id}” do cluster cluster command role.create_command version version action :nothing subscribes :run, resources(“execute[pg_createcluster:#{version}:#{cluster}]”) end end What about the recipes?
  24. • Get Chef http://opscode.com • Get started http://docs.opscode.com • Get

    Ingredients (docs, too!) http://github.com/zobar/ingredients • Learn from example http://github.com/zobar/postgresql-ingredients How do I start?
  25. Any language, any framework, anything! Every other Tuesday from 7-9pm

    Cowork Buffalo, Delaware & Chippewa http://openhack.github.com/buffalo OpenHack Buffalo
  26. This presentation typeset in P22 Foxtrot Pro and Foxtrot Sans

    Pro Excellent selection of interesting fonts Headquartered in Buffalo http://p22.com http://myfonts.com/foundry/p22 P22 Type Foundry