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

Reprogramming Chef

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Reprogramming Chef

Avatar for Steven Danna

Steven Danna

July 31, 2014
Tweet

Other Decks in Technology

Transcript

  1. package "nginx"! ! template "/etc/nginx.conf" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! notifies :restart, "service[nginx]"! end! ! service "nginx" do! action [:enable, :start]! end!
  2. package "nginx"! ! template "/etc/nginx.conf" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! notifies :restart, "service[nginx]"! end! ! service "nginx" do! action [:enable, :start]! end!
  3. package "nginx"! ! template "/etc/nginx.conf" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! notifies :restart, "service[nginx]"! end! ! service "nginx" do! action [:enable, :start]! end!
  4. package "nginx"! ! template "/etc/nginx.conf" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! notifies :restart, "service[nginx]"! end! ! service "nginx" do! action [:enable, :start]! end!
  5. package "nginx"! ! template "/etc/nginx.conf" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! notifies :restart, "service[nginx]"! end! ! service "nginx" do! action [:enable, :start]! end!
  6. packages = [ "emacs",! "tmux",! "irssi" ]! ! packages.each do

    |pkg|! package pkg do! action :install! end! end!
  7. Ohai Plugins Knife Plugins Start, Report, and Error Handlers Event

    Subscribers and Output Formatters Definitions LWRPs
  8. Ticket #1: The LDAP Flood Ohai is trying to pull

    in my Corporation’s entire LDAP directory on every run. Please help!
  9. Etc.passwd do |entry|! user_passwd_entry = Mash.new(:dir => entry.dir, ! !

    ! ! ! ! ! ! ! ! ! ! ! :gid => entry.gid, ! ! ! ! ! ! ! ! ! ! ! ! ! :uid => entry.uid, ! ! ! ! ! ! ! ! ! ! ! ! :shell => entry.shell, ! ! ! ! ! ! ! ! ! ! ! ! ! :gecos => entry.gecos)! user_passwd_entry.each_value {|v| fix_encoding(v)}! etc[:passwd][fix_encoding(entry.name)] = user_passwd_entry! end lib/ohai/plugins/passwd.rb
  10. static VALUE! passwd_iterate(void)! {! struct passwd *pw;! ! setpwent();! while

    (pw = getpwent()) {! rb_yield(setup_passwd(pw));! }! return Qnil;! }! ext/etc/etc.c
  11. “The getpwent() function returns a pointer to a structure containing

    the broken-out fields of a record from the password database (e.g., the local password file /etc/passwd, NIS, and LDAP)”
  12. provides 'etc'! ! etc Mash.new! etc[:passwd] = Mash.new! etc[:group] =

    Mash.new! ! File.open("/etc/passwd", "r") do |f|! f.each_line do |line|! etc[:passwd].merge!(parse_passwd_line(line))! end! end! ! File.open("/etc/group", "r") do |f|! f.each_line do |line|! etc[:group].merge!(parse_group_line(line))! end! end! ! # parse_passwd_line and parse_group_line not shown!
  13. Open Classes, Part I module StringExtensions! def leet(str=self)! str.gsub("e", "3").gsub("o",

    "0")! end! end! ! class String! include StringExtensions! end! ! puts "hello, world".leet!
  14. Open Classes, Part I module StringExtensions! def leet(str=self)! str.gsub("e", "3").gsub("o",

    "0")! end! end! ! String.send(:include, StringExtensions)! ! ! puts "hello, world".leet!
  15. Ticket #2: The ugly search I have a recipe that

    configures remote rsyslog. But a search for the syslog server isn’t returning what I expect. Can you help?
  16. What happens if the node running the recipe is the

    rsyslog-server, and this is the first run?
  17. rsyslog_server = search(:node, ! "role:rsyslog-server").sort.first! ! if rsyslog_server.nil? ! rsyslog_server

    = node! else! ! template "/etc/rsyslog.conf" do! variables :server => rsyslog_server['fqdn']! end!
  18. rsyslog_server = search(:node, ! "role:rsyslog-server").sort.first! ! if rsyslog_server.nil? && !

    node['roles'].include?('rsyslog-server')! rsyslog_server = node! else! Chef::Application.fatal!(‘No rsyslog-server found.')! end! ! template "/etc/rsyslog.conf" do! variables :server => rsyslog_server['fqdn']! end!
  19. “That is a bit better, but I the recipe is

    a lot uglier and I want to use a similar pattern in other cookbooks.”
  20. module YourCorp! module DSL! def node_with_role(role)! candidates = search(:node, "roles:#{role}").sort!

    candidates << node if node['roles'].include?(role)! if candidates.empty?! fail "No node found with role:#{role}"! else! candidates.first! end! end! end! end! ! Chef::Recipe.send(:include, YourCorp::DSL)!
  21. Open Classes, Part II class String! def upcase! # Keep

    your workstation locked!! "LOLOLOL"! end! end! ! puts "hello, world".upcase!
  22. Open Classes, Part II class String! alias_method :old_upcase, :upcase! def

    upcase! old_upcase + "!!!"! end! end! ! puts "hello, world".upcase!
  23. Ticket #3: The Poor Typist Every time I typo my

    nginx configuration template, the service fails to restart properly. Why can’t Chef help me?!
  24. package "nginx"! ! template "/etc/nginx.conf" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! notifies :restart, "service[nginx]"! end! ! service "nginx" do! action [:enable, :start]! end!
  25. package "nginx"! ! template "/etc/nginx.conf.temp" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! notifies :run, "bash[check-nginx-template]", :immediately! end! ! bash "check-nginx-template" do! command "nginx -t -c /etc/nginx.conf.temp"! notifies :create, "file[/etc/nginx.conf]", :immediately! end! ! file "/etc/nginx.conf" do! content lazy { ::File.read(“/etc/nginx.conf.temp”) }! action :nothing! notifies :restart, "service[nginx]", :immediately! end! ! service "nginx" do! action [:enable, :start]! end!
  26. # This should succeed! template "/tmp/foo" do! verify do |path|!

    true! end! end! ! # This should raise an error! template "/tmp/bar" do! verify do |path|! false! end! end!
  27. package "nginx"! ! template "/etc/nginx.conf" do! source "nginx.conf.erb"! variables :doc_root

    => "/var/www"! verify do |path|! `nginx -t -c #{path}`! $? == 0! end! notifies :restart, "service[nginx]"! end! ! service "nginx" do! action [:enable, :start]! end!
  28. class Chef::Resource::Template < Chef::Resource::File! def verify(&block)! if block_given? ! @verify_block=block!

    else! @verify_block! end! end! end! ! class Chef::Provider::File! alias_method :old_dcc, :do_contents_changes! def do_contents_changes! do_verify if !@new_resource.verify.nil?! old_dcc! end! ! def do_verify! Chef::Log.debug "Validating rendered file"! unless @new_resource.verify.call(tempfile.path)! raise Chef::Exceptions::ValidationFailed, "Could not validate rendered file"! end! end! end!
  29. On Reprogrammable System Customizing Chef Chef Sugar Passwd_min Ohai Plugin

    http://stackoverflow.com/a/4471202/618304 Stack Overflow Answer https://stevendanna.github.io/blog/2013/04/13/passwd-min-ohai-plugin/ https://sethvargo.github.io/chef-sugar/ http://shop.oreilly.com/product/0636920032984.do http://www.confreaks.com/videos/374-rubyconf2010-the-polite-programmer-s-guide ruby-etiquette Talk by Jim Weirich http://martinfowler.com/bliki/InternalReprogrammability.html