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