Skip to content

Commit 6a38db5

Browse files
adamhjkdanielsdeleo
authored andcommitted
First pass at cookbook manifest gen - CHEF-1144
1 parent fc032dc commit 6a38db5

5 files changed

Lines changed: 205 additions & 120 deletions

File tree

chef-server-api/app/controllers/application.rb

Lines changed: 2 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -93,56 +93,6 @@ def access_denied
9393
raise Unauthorized, "You must authenticate first!"
9494
end
9595

96-
# Load a cookbook and return a hash with a list of all the files of a
97-
# given segment (attributes, recipes, definitions, libraries)
98-
#
99-
# === Parameters
100-
# cookbook_id<String>:: The cookbook to load
101-
# segment<Symbol>:: :attributes, :recipes, :definitions, :libraries
102-
#
103-
# === Returns
104-
# <Hash>:: A hash consisting of the short name of the file in :name, and the full path
105-
# to the file in :file.
106-
def load_cookbook_segment(cookbook, segment)
107-
files_list = segment_files(segment, cookbook)
108-
109-
files = Hash.new
110-
files_list.each do |f|
111-
full = File.expand_path(f)
112-
name = File.basename(full)
113-
files[name] = {
114-
:name => name,
115-
:file => full,
116-
}
117-
end
118-
files
119-
end
120-
121-
def segment_files(segment, cookbook)
122-
files_list = nil
123-
case segment
124-
when :attributes
125-
files_list = cookbook.attribute_files
126-
when :recipes
127-
files_list = cookbook.recipe_files
128-
when :definitions
129-
files_list = cookbook.definition_files
130-
when :libraries
131-
files_list = cookbook.lib_files
132-
when :providers
133-
files_list = cookbook.provider_files
134-
when :resources
135-
files_list = cookbook.resource_files
136-
when :files
137-
files_list = cookbook.remote_files
138-
when :templates
139-
files_list = cookbook.template_files
140-
else
141-
raise ArgumentError, "segment must be one of :attributes, :recipes, :definitions, :remote_files, :template_files, :resources, :providers or :libraries"
142-
end
143-
files_list
144-
end
145-
14696
def specific_cookbooks(node_name, cl)
14797
valid_cookbooks = Hash.new
14898
begin
@@ -169,66 +119,7 @@ def expand_cookbook_deps(valid_cookbooks, cl, recipe)
169119
end
170120
valid_cookbooks
171121
end
172-
173-
def load_cookbook_files(cookbook)
174-
response = {
175-
:recipes => Array.new,
176-
:definitions => Array.new,
177-
:libraries => Array.new,
178-
:attributes => Array.new,
179-
:files => Array.new,
180-
:templates => Array.new,
181-
:resources => Array.new,
182-
:providers => Array.new
183-
}
184-
[ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates ].each do |segment|
185-
segment_files(segment, cookbook).each do |sf|
186-
next if File.directory?(sf)
187-
file_name = nil
188-
file_url = nil
189-
file_specificity = nil
190-
191-
if segment == :templates || segment == :files
192-
mo = sf.match("cookbooks/#{cookbook.name}/#{segment}/(.+?)/(.+)")
193-
unless mo
194-
Chef::Log.debug("Skipping file #{sf}, as it doesn't have a proper segment.")
195-
next
196-
end
197-
specificity = mo[1]
198-
file_name = mo[2]
199-
url_options = { :cookbook_id => cookbook.name.to_s, :segment => segment, :id => file_name }
200-
201-
case specificity
202-
when "default"
203-
when /^host-(.+)$/
204-
url_options[:fqdn] = $1
205-
when /^(.+)-(.+)$/
206-
url_options[:platform] = $1
207-
url_options[:version] = $2
208-
when /^(.+)$/
209-
url_options[:platform] = $1
210-
end
211-
212-
file_specificity = specificity
213-
file_url = absolute_url(:cookbook_segment, url_options)
214-
else
215-
mo = sf.match("cookbooks/#{cookbook.name}/#{segment}/(.+)")
216-
file_name = mo[1]
217-
url_options = { :cookbook_id => cookbook.name.to_s, :segment => segment, :id => file_name }
218-
file_url = absolute_url(:cookbook_segment, url_options)
219-
end
220-
rs = {
221-
:name => file_name,
222-
:uri => file_url,
223-
:checksum => checksum(sf)
224-
}
225-
rs[:specificity] = file_specificity if file_specificity
226-
response[segment] << rs
227-
end
228-
end
229-
response
230-
end
231-
122+
232123
def load_all_files(node_name=nil)
233124
cl = Chef::CookbookLoader.new
234125
valid_cookbooks = node_name ? specific_cookbooks(node_name, cl) : {}
@@ -237,7 +128,7 @@ def load_all_files(node_name=nil)
237128
if node_name
238129
next unless valid_cookbooks[cookbook.name.to_s]
239130
end
240-
cookbook_list[cookbook.name.to_s] = load_cookbook_files(cookbook)
131+
cookbook_list[cookbook.name.to_s] = cookbook.generate_manifest { |opts| absolute_slice_url(:cookbook_segment, opts) }
241132
end
242133
cookbook_list
243134
end

chef-server-api/app/controllers/cookbooks.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,8 @@ def show
4646
rescue ArgumentError => e
4747
raise NotFound, "Cannot find a cookbook named #{params[:id]}"
4848
end
49-
results = load_cookbook_files(cookbook)
50-
results[:name] = cookbook.name.to_s
51-
results[:metadata] = cl.metadata[cookbook.name.to_sym]
52-
display results
49+
cookbook.generate_manifest { |opts| absolute_slice_url(:cookbook_segment, opts) }
50+
display cookbook
5351
end
5452

5553
def show_segment

chef/lib/chef/cookbook.rb

Lines changed: 197 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,44 @@
2626
class Chef
2727
class Cookbook
2828
include Chef::Mixin::ConvertToClassName
29+
include Chef::Mixin::Checksum
30+
include Chef::IndexQueue::Indexable
2931

30-
attr_accessor :definition_files, :template_files, :remote_files,
31-
:lib_files, :resource_files, :provider_files, :name
32-
attr_reader :recipe_files, :attribute_files
32+
attr_accessor :definition_files, :template_files, :remote_files,
33+
:lib_files, :resource_files, :provider_files, :name, :manifest,
34+
:metadata, :metadata_files, :status, :couchdb_rev, :couchdb, :version
35+
attr_reader :recipe_files, :attribute_files, :couchdb_id
36+
37+
DESIGN_DOCUMENT = {
38+
"version" => 1,
39+
"language" => "javascript",
40+
"views" => {
41+
"all" => {
42+
"map" => <<-EOJS
43+
function(doc) {
44+
if (doc.chef_type == "cookbook") {
45+
emit(doc.name, doc);
46+
}
47+
}
48+
EOJS
49+
},
50+
"all_id" => {
51+
"map" => <<-EOJS
52+
function(doc) {
53+
if (doc.chef_type == "cookbook") {
54+
emit(doc.name, doc.name);
55+
}
56+
}
57+
EOJS
58+
}
59+
}
60+
}
3361

3462
# Creates a new Chef::Cookbook object.
3563
#
3664
# === Returns
3765
# object<Chef::Cookbook>:: Duh. :)
38-
def initialize(name)
66+
def initialize(name, couchdb=nil)
3967
@name = name
4068
@attribute_files = Array.new
4169
@attribute_names = Hash.new
@@ -47,6 +75,18 @@ def initialize(name)
4775
@lib_files = Array.new
4876
@resource_files = Array.new
4977
@provider_files = Array.new
78+
@metadata_files = Array.new
79+
@couchdb_id = nil
80+
@couchdb = couchdb || Chef::CouchDB.new
81+
@couchdb_rev = nil
82+
@status = :ready
83+
@manifest = nil
84+
@version = nil
85+
@metadata = {}
86+
end
87+
88+
def full_name
89+
"#{name}-#{version}"
5090
end
5191

5292
# Loads all the library files in this cookbook via require.
@@ -172,6 +212,159 @@ def load_recipe(name, node, collection=nil, definitions=nil, cookbook_loader=nil
172212
recipe
173213
end
174214

215+
def segment_files(segment)
216+
files_list = nil
217+
case segment
218+
when :attributes
219+
files_list = attribute_files
220+
when :recipes
221+
files_list = recipe_files
222+
when :definitions
223+
files_list = definition_files
224+
when :libraries
225+
files_list = lib_files
226+
when :providers
227+
files_list = provider_files
228+
when :resources
229+
files_list = resource_files
230+
when :files
231+
files_list = remote_files
232+
when :templates
233+
files_list = template_files
234+
else
235+
raise ArgumentError, "segment must be one of :attributes, :recipes, :definitions, :remote_files, :template_files, :resources, :providers or :libraries"
236+
end
237+
files_list
238+
end
239+
240+
def to_json(*a)
241+
result = self.manifest ? self.manifest : self.generate_manifest
242+
result['json_class'] = self.class.name
243+
result['chef_type'] = 'cookbook'
244+
result["_rev"] = @couchdb_rev if @couchdb_rev
245+
result.to_json(*a)
246+
end
247+
248+
def self.json_create(o)
249+
cookbook = new(o["cookbook_name"])
250+
if o.has_key?('_rev')
251+
cookbook.couchdb_rev = o["_rev"] if o.has_key?("_rev")
252+
o.delete("_rev")
253+
end
254+
if o.has_key?("_id")
255+
cookbook.couchdb_id = o["_id"] if o.has_key?("_id")
256+
cookbook.index_id = cookbook.couchdb_id
257+
o.delete("_id")
258+
end
259+
cookbook.manifest = o
260+
cookbook.metadata = o["metadata"]
261+
cookbook.version = o["version"]
262+
cookbook
263+
end
264+
265+
def generate_manifest(&url_generation)
266+
response = {
267+
:recipes => Array.new,
268+
:definitions => Array.new,
269+
:libraries => Array.new,
270+
:attributes => Array.new,
271+
:files => Array.new,
272+
:templates => Array.new,
273+
:resources => Array.new,
274+
:providers => Array.new
275+
}
276+
[ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates ].each do |segment|
277+
segment_files(segment).each do |sf|
278+
next if File.directory?(sf)
279+
280+
file_name = nil
281+
file_url = nil
282+
file_specificity = nil
283+
url_options = nil
284+
285+
if segment == :templates || segment == :files
286+
mo = sf.match("cookbooks/#{name}/#{segment}/(.+?)/(.+)")
287+
unless mo
288+
Chef::Log.debug("Skipping file #{sf}, as it doesn't have a proper segment.")
289+
next
290+
end
291+
specificity = mo[1]
292+
file_name = mo[2]
293+
url_options = { :cookbook_id => name.to_s, :segment => segment, :id => file_name }
294+
295+
case specificity
296+
when "default"
297+
when /^host-(.+)$/
298+
url_options[:fqdn] = $1
299+
when /^(.+)-(.+)$/
300+
url_options[:platform] = $1
301+
url_options[:version] = $2
302+
when /^(.+)$/
303+
url_options[:platform] = $1
304+
end
305+
306+
file_specificity = specificity
307+
else
308+
mo = sf.match("cookbooks/#{name}/#{segment}/(.+)")
309+
file_name = mo[1]
310+
url_options = { :cookbook_id => name.to_s, :segment => segment, :id => file_name }
311+
end
312+
313+
if url_generation
314+
file_url = url_generation.call(url_options)
315+
else
316+
file_url = nil
317+
end
318+
319+
rs = {
320+
:name => file_name,
321+
:uri => file_url,
322+
:path => sf.match("cookbooks/#{name}/(#{segment}/.+)")[1],
323+
:checksum => checksum(sf)
324+
}
325+
rs[:specificity] = file_specificity if file_specificity
326+
response[segment] << rs
327+
end
328+
end
329+
response[:cookbook_name] = name.to_s
330+
response[:metadata] = metadata
331+
response[:version] = metadata.version
332+
@version = metadata.version
333+
response[:name] = full_name
334+
@manifest = response
335+
end
336+
337+
##
338+
# Couchdb
339+
##
340+
341+
def self.create_design_document(couchdb=nil)
342+
(couchdb || Chef::CouchDB.new).create_design_document("cookbooks", DESIGN_DOCUMENT)
343+
end
344+
345+
def self.cdb_list(inflate=false, couchdb=nil)
346+
rs = (couchdb || Chef::CouchDB.new).list("cookbooks", inflate)
347+
lookup = (inflate ? "value" : "key")
348+
rs["rows"].collect { |r| r[lookup] }
349+
end
350+
351+
def self.cdb_load(name, couchdb=nil)
352+
(couchdb || Chef::CouchDB.new).load("cookbook", full_name)
353+
end
354+
355+
def cdb_destroy
356+
(couchdb || Chef::CouchDB.new).delete("cookbook", full_name, @couchdb_rev)
357+
end
358+
359+
def cdb_save
360+
@couchdb_rev = @couchdb.store("cookbook", full_name, self)["rev"]
361+
end
362+
363+
def couchdb_id=(value)
364+
@couchdb_id = value
365+
self.index_id = value
366+
end
367+
175368
private
176369

177370
def shorten_name(name)

chef/lib/chef/cookbook_loader.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ def load_cookbooks
112112
@cookbook[cookbook].lib_files = cookbook_settings[cookbook][:lib_files].values
113113
@cookbook[cookbook].resource_files = cookbook_settings[cookbook][:resource_files].values
114114
@cookbook[cookbook].provider_files = cookbook_settings[cookbook][:provider_files].values
115+
@cookbook[cookbook].metadata_files = cookbook_settings[cookbook][:metadata_files]
115116
@metadata[cookbook] = Chef::Cookbook::Metadata.new(@cookbook[cookbook])
116117
cookbook_settings[cookbook][:metadata_files].each do |meta_json|
117118
begin
@@ -121,6 +122,7 @@ def load_cookbooks
121122
raise
122123
end
123124
end
125+
@cookbook[cookbook].metadata = @metadata[cookbook]
124126
end
125127
end
126128

0 commit comments

Comments
 (0)