Class: Chef::Cookbook

Inherits:
Object
  • Object
show all
Defined in:
lib/devstructure/chef.rb

Overview

A cookbook is a collection of Chef resources plus the files and other supporting objects needed to run it.

Instance Method Summary collapse

Constructor Details

#initialize(name, comment, options = {}) ⇒ Cookbook

The name and options given to a cookbook become the filename and the parameters set in ‘metadata.rb`. The comment is a bit awkward and exists so the disclaimer supplied with all blueprints can be shown at the top of `metadata.rb`.



29
30
31
32
# File 'lib/devstructure/chef.rb', line 29

def initialize(name, comment, options={})
  @name, @comment, @options = name, comment, options
  @resources, @files = [], {}
end

Instance Method Details

#<<(resource) ⇒ Object

Resources should be added in the order they’re required to run. That is how Chef manages dependencies.



36
37
38
# File 'lib/devstructure/chef.rb', line 36

def <<(resource)
  @resources << resource
end

#apt_package(name, options = {}) ⇒ Object

In Chef, there are lots of top-level helpers for creating resources. This selection of almost-API-alikes facilitates the same thing for a ‘DevStructure::Chef::Cookbook`.



43
44
45
# File 'lib/devstructure/chef.rb', line 43

def apt_package(name, options={})
  self << Chef::Resource.new(:apt_package, name, options)
end

#cookbook_file(name, content, options = {}) ⇒ Object



58
59
60
61
# File 'lib/devstructure/chef.rb', line 58

def cookbook_file(name, content, options={})
  self << Chef::Resource.new(:cookbook_file, name, options)
  @files[name] = content
end

#directory(name, options = {}) ⇒ Object



52
53
54
# File 'lib/devstructure/chef.rb', line 52

def directory(name, options={})
  self << Chef::Resource.new(:directory, name, options)
end

#execute(name, options = {}) ⇒ Object



49
50
51
# File 'lib/devstructure/chef.rb', line 49

def execute(name, options={})
  self << Chef::Resource.new(:execute, name, options)
end

#gem_package(name, options = {}) ⇒ Object



46
47
48
# File 'lib/devstructure/chef.rb', line 46

def gem_package(name, options={})
  self << Chef::Resource.new(:gem_package, name, options)
end


55
56
57
# File 'lib/devstructure/chef.rb', line 55

def link(name, options={})
  self << Chef::Resource.new(:link, name, options)
end

#to_gz(io) ⇒ Object

This is where the magic happens. The generated Chef cookbook will come as a tarball, written into whatever ‘IO`-like object is passed here. The DevStructure website will pass `StringIO` while the command-line tools will pass `File`.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/devstructure/chef.rb', line 67

def to_gz(io)
  mtime = Time.now
  gz = Zlib::GzipWriter.new(io)
  tar = Archive::Tar::Minitar::Writer.new(gz)
  tar.mkdir @name, :mode => 0755, :mtime => mtime

  # `metadata.rb` contains the typical DevStructure comment, a
  # declaration of support for Ubuntu 10.04 or better, and any other
  # metadata passed to the constructor of this `Cookbook`.
  @options[:supports] ||= ["ubuntu", ">= 10.04"]
   = ([@comment] + @options.sort.collect do |key, value|
    "#{key} #{[value].flatten.collect { |v| v.inspect }.join(", ")}\n"
  end).join("")
  tar.add_file_simple("#{@name}/metadata.rb", {
    :mode => 0644,
    :size => .length,
    :mtime => mtime
  }) { |w| w.write  }

  # Build the recipe.  Each resource handles its own stringification so
  # the work done here amounts to gathering up a string and placing it
  # in a file in the tarball.
  resources = @resources.collect { |resource| resource.to_s }.join("")
  tar.mkdir "#{@name}/recipes", :mode => 0755, :mtime => mtime
  tar.add_file_simple("#{@name}/recipes/default.rb", {
    :mode => 0644,
    :size => resources.length,
    :mtime => mtime
  }) { |w| w.write resources }

  # Include any files referenced by `cookbook_file` resources.  They
  # all appear in `files/default/` as if that is the root of the
  # filesystem.
  if 0 < @files.length
    tar.mkdir "#{@name}/files", :mode => 0755, :mtime => mtime
    tar.mkdir "#{@name}/files/default", :mode => 0755, :mtime => mtime
    @files.each do |pathname, content|
      dirnames = File.dirname(pathname).split("/")
      dirnames.shift
      (0..(dirnames.length - 1)).each do |i|
        tar.mkdir "#{@name}/files/default/#{dirnames[0..i].join("/")}",
          :mode => 0755, :mtime => mtime
      end
      tar.add_file_simple("#{@name}/files/default#{pathname}", {
        :mode => 0644,
        :size => content.length,
        :mtime => mtime
      }) { |w| w.write content }
    end
  end

  # Return the finalized tarball.
  tar.close
  gz.close
  io

end