chef 0.9.18 → 0.10.0.beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +0 -3
- data/distro/arch/etc/rc.d/chef-server +0 -4
- data/distro/arch/etc/rc.d/chef-server-webui +0 -4
- data/distro/arch/etc/rc.d/chef-solr +0 -4
- data/distro/arch/etc/rc.d/chef-solr-indexer +0 -4
- data/lib/chef.rb +3 -3
- data/lib/chef/api_client.rb +1 -1
- data/lib/chef/application.rb +11 -1
- data/lib/chef/application/client.rb +18 -22
- data/lib/chef/application/knife.rb +28 -29
- data/lib/chef/application/solo.rb +14 -12
- data/lib/chef/client.rb +112 -54
- data/lib/chef/config.rb +4 -0
- data/lib/chef/cookbook/chefignore.rb +66 -0
- data/lib/chef/cookbook/cookbook_collection.rb +6 -5
- data/lib/chef/cookbook/cookbook_version_loader.rb +151 -0
- data/lib/chef/cookbook/file_system_file_vendor.rb +10 -8
- data/lib/chef/cookbook/metadata.rb +200 -108
- data/lib/chef/cookbook_loader.rb +39 -163
- data/lib/chef/cookbook_uploader.rb +100 -78
- data/lib/chef/cookbook_version.rb +92 -47
- data/lib/chef/cookbook_version_selector.rb +163 -0
- data/lib/chef/couchdb.rb +9 -1
- data/lib/chef/data_bag.rb +1 -1
- data/lib/chef/data_bag_item.rb +1 -1
- data/lib/chef/encrypted_data_bag_item.rb +126 -0
- data/lib/chef/environment.rb +386 -0
- data/lib/chef/exceptions.rb +82 -1
- data/lib/chef/index_queue/amqp_client.rb +15 -12
- data/lib/chef/index_queue/indexable.rb +38 -4
- data/lib/chef/json_compat.rb +3 -3
- data/lib/chef/knife.rb +97 -202
- data/lib/chef/knife/bootstrap.rb +27 -61
- data/lib/chef/knife/bootstrap/archlinux-gems.erb +4 -2
- data/lib/chef/knife/bootstrap/centos5-gems.erb +6 -15
- data/lib/chef/knife/bootstrap/fedora13-gems.erb +3 -4
- data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +2 -2
- data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +6 -5
- data/lib/chef/knife/client_bulk_delete.rb +6 -3
- data/lib/chef/knife/client_create.rb +13 -10
- data/lib/chef/knife/client_delete.rb +10 -7
- data/lib/chef/knife/client_edit.rb +9 -6
- data/lib/chef/knife/client_list.rb +8 -5
- data/lib/chef/knife/client_reregister.rb +9 -6
- data/lib/chef/knife/client_show.rb +9 -6
- data/lib/chef/knife/configure.rb +15 -19
- data/lib/chef/knife/configure_client.rb +4 -4
- data/lib/chef/knife/cookbook_bulk_delete.rb +11 -8
- data/lib/chef/knife/cookbook_create.rb +120 -55
- data/lib/chef/knife/cookbook_delete.rb +18 -12
- data/lib/chef/knife/cookbook_download.rb +10 -6
- data/lib/chef/knife/cookbook_list.rb +15 -6
- data/lib/chef/knife/cookbook_metadata.rb +41 -21
- data/lib/chef/knife/cookbook_metadata_from_file.rb +4 -0
- data/lib/chef/knife/cookbook_show.rb +16 -5
- data/lib/chef/knife/cookbook_site_download.rb +2 -2
- data/lib/chef/knife/cookbook_site_share.rb +18 -13
- data/lib/chef/knife/cookbook_site_unshare.rb +7 -4
- data/lib/chef/knife/cookbook_site_vendor.rb +21 -18
- data/lib/chef/knife/cookbook_test.rb +14 -14
- data/lib/chef/knife/cookbook_upload.rb +91 -40
- data/lib/chef/knife/data_bag_create.rb +41 -6
- data/lib/chef/knife/data_bag_delete.rb +5 -3
- data/lib/chef/knife/data_bag_edit.rb +55 -11
- data/lib/chef/knife/data_bag_from_file.rb +47 -7
- data/lib/chef/knife/data_bag_list.rb +4 -1
- data/lib/chef/knife/data_bag_show.rb +44 -4
- data/lib/chef/knife/environment_create.rb +53 -0
- data/lib/chef/knife/environment_delete.rb +45 -0
- data/lib/chef/knife/environment_edit.rb +45 -0
- data/lib/chef/knife/environment_from_file.rb +39 -0
- data/lib/chef/knife/environment_list.rb +42 -0
- data/lib/chef/knife/environment_show.rb +46 -0
- data/lib/chef/knife/exec.rb +1 -1
- data/lib/chef/knife/index_rebuild.rb +8 -9
- data/lib/chef/knife/node_bulk_delete.rb +9 -6
- data/lib/chef/knife/node_create.rb +9 -6
- data/lib/chef/knife/node_delete.rb +10 -7
- data/lib/chef/knife/node_edit.rb +129 -10
- data/lib/chef/knife/node_from_file.rb +10 -7
- data/lib/chef/knife/node_list.rb +11 -6
- data/lib/chef/knife/node_run_list_add.rb +10 -7
- data/lib/chef/knife/node_run_list_remove.rb +9 -6
- data/lib/chef/knife/node_show.rb +15 -7
- data/lib/chef/knife/recipe_list.rb +4 -3
- data/lib/chef/knife/role_bulk_delete.rb +9 -6
- data/lib/chef/knife/role_create.rb +9 -6
- data/lib/chef/knife/role_delete.rb +10 -7
- data/lib/chef/knife/role_edit.rb +11 -8
- data/lib/chef/knife/role_from_file.rb +10 -7
- data/lib/chef/knife/role_list.rb +8 -5
- data/lib/chef/knife/role_show.rb +11 -8
- data/lib/chef/knife/search.rb +33 -10
- data/lib/chef/knife/ssh.rb +33 -61
- data/lib/chef/knife/status.rb +7 -4
- data/lib/chef/knife/subcommand_loader.rb +101 -0
- data/lib/chef/knife/tag_create.rb +31 -0
- data/lib/chef/knife/tag_delete.rb +31 -0
- data/lib/chef/knife/tag_list.rb +29 -0
- data/lib/chef/knife/ui.rb +229 -0
- data/lib/chef/knife/windows_bootstrap.rb +8 -5
- data/lib/chef/log.rb +5 -59
- data/lib/chef/mash.rb +211 -0
- data/lib/chef/mixins.rb +1 -2
- data/lib/chef/nil_argument.rb +3 -0
- data/lib/chef/node.rb +96 -34
- data/lib/chef/platform.rb +27 -0
- data/lib/chef/provider/cookbook_file.rb +21 -20
- data/lib/chef/provider/deploy/revision.rb +3 -0
- data/lib/chef/provider/file.rb +20 -11
- data/lib/chef/provider/git.rb +26 -26
- data/lib/chef/provider/group/aix.rb +70 -0
- data/lib/chef/provider/group/groupadd.rb +7 -4
- data/lib/chef/provider/group/usermod.rb +1 -1
- data/lib/chef/provider/package.rb +28 -28
- data/lib/chef/provider/package/dpkg.rb +1 -1
- data/lib/chef/provider/package/portage.rb +50 -39
- data/lib/chef/provider/package/rubygems.rb +1 -1
- data/lib/chef/provider/package/zypper.rb +3 -20
- data/lib/chef/provider/remote_directory.rb +0 -2
- data/lib/chef/provider/remote_file.rb +2 -3
- data/lib/chef/provider/service/arch.rb +28 -35
- data/lib/chef/provider/service/simple.rb +1 -1
- data/lib/chef/provider/subversion.rb +22 -22
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/recipe.rb +10 -12
- data/lib/chef/resource.rb +49 -42
- data/lib/chef/resource/gem_package.rb +7 -3
- data/lib/chef/resource/git.rb +5 -5
- data/lib/chef/resource/package.rb +7 -7
- data/lib/chef/resource/scm.rb +2 -1
- data/lib/chef/resource/solaris_package.rb +0 -1
- data/lib/chef/resource/yum_package.rb +0 -1
- data/lib/chef/rest.rb +7 -16
- data/lib/chef/rest/rest_request.rb +0 -16
- data/lib/chef/role.rb +67 -13
- data/lib/chef/run_context.rb +37 -21
- data/lib/chef/run_list.rb +30 -15
- data/lib/chef/run_list/run_list_expansion.rb +41 -20
- data/lib/chef/run_list/run_list_item.rb +20 -6
- data/lib/chef/run_list/versioned_recipe_list.rb +68 -0
- data/lib/chef/runner.rb +7 -15
- data/lib/chef/search/query.rb +12 -7
- data/lib/chef/shef.rb +6 -7
- data/lib/chef/shef/shef_session.rb +40 -35
- data/lib/chef/shell_out.rb +22 -201
- data/lib/chef/shell_out/unix.rb +224 -0
- data/lib/chef/shell_out/windows.rb +95 -0
- data/lib/chef/solr_query.rb +187 -0
- data/lib/chef/solr_query/lucene.treetop +145 -0
- data/lib/chef/solr_query/lucene_nodes.rb +285 -0
- data/lib/chef/solr_query/query_transform.rb +65 -0
- data/lib/chef/solr_query/solr_http_request.rb +118 -0
- data/lib/chef/version.rb +4 -2
- data/lib/chef/version_class.rb +70 -0
- data/lib/chef/version_constraint.rb +116 -0
- metadata +68 -37
- data/lib/chef/cookbook/metadata/version.rb +0 -87
- data/lib/chef/knife/bluebox_images_list.rb +0 -54
- data/lib/chef/knife/bluebox_server_create.rb +0 -157
- data/lib/chef/knife/bluebox_server_delete.rb +0 -63
- data/lib/chef/knife/bluebox_server_list.rb +0 -59
- data/lib/chef/knife/ec2_instance_data.rb +0 -46
- data/lib/chef/knife/ec2_server_create.rb +0 -218
- data/lib/chef/knife/ec2_server_delete.rb +0 -87
- data/lib/chef/knife/ec2_server_list.rb +0 -89
- data/lib/chef/knife/rackspace_server_create.rb +0 -184
- data/lib/chef/knife/rackspace_server_delete.rb +0 -57
- data/lib/chef/knife/rackspace_server_list.rb +0 -59
- data/lib/chef/knife/slicehost_images_list.rb +0 -53
- data/lib/chef/knife/slicehost_server_create.rb +0 -103
- data/lib/chef/knife/slicehost_server_delete.rb +0 -61
- data/lib/chef/knife/slicehost_server_list.rb +0 -64
- data/lib/chef/knife/terremark_server_create.rb +0 -152
- data/lib/chef/knife/terremark_server_delete.rb +0 -87
- data/lib/chef/knife/terremark_server_list.rb +0 -77
- data/lib/chef/mixin/find_preferred_file.rb +0 -92
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
#
|
|
2
1
|
# Author:: Adam Jacob (<adam@opscode.com>)
|
|
3
2
|
# Author:: Nuo Yan (<nuo@opscode.com>)
|
|
4
3
|
# Author:: Christopher Walters (<cw@opscode.com>)
|
|
5
4
|
# Author:: Tim Hinderliter (<tim@opscode.com>)
|
|
6
|
-
#
|
|
5
|
+
# Author:: Seth Falcon (<seth@opscode.com>)
|
|
6
|
+
# Copyright:: Copyright 2008-2010 Opscode, Inc.
|
|
7
7
|
# License:: Apache License, Version 2.0
|
|
8
8
|
#
|
|
9
9
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
10
|
# you may not use this file except in compliance with the License.
|
|
11
11
|
# You may obtain a copy of the License at
|
|
12
|
-
#
|
|
12
|
+
#
|
|
13
13
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
-
#
|
|
14
|
+
#
|
|
15
15
|
# Unless required by applicable law or agreed to in writing, software
|
|
16
16
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
17
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
@@ -25,6 +25,8 @@ require 'chef/resource_definition_list'
|
|
|
25
25
|
require 'chef/recipe'
|
|
26
26
|
require 'chef/cookbook/file_vendor'
|
|
27
27
|
require 'chef/checksum'
|
|
28
|
+
require 'chef/cookbook/metadata'
|
|
29
|
+
require 'chef/version_class'
|
|
28
30
|
|
|
29
31
|
class Chef
|
|
30
32
|
# == Chef::CookbookVersion
|
|
@@ -37,16 +39,17 @@ class Chef
|
|
|
37
39
|
# recipe_filenames.insert) should dirty the manifest so it gets regenerated.
|
|
38
40
|
class CookbookVersion
|
|
39
41
|
include Chef::IndexQueue::Indexable
|
|
42
|
+
include Comparable
|
|
40
43
|
|
|
41
44
|
COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
|
|
42
|
-
|
|
45
|
+
|
|
43
46
|
DESIGN_DOCUMENT = {
|
|
44
47
|
"version" => 7,
|
|
45
48
|
"language" => "javascript",
|
|
46
49
|
"views" => {
|
|
47
50
|
"all" => {
|
|
48
51
|
"map" => <<-EOJS
|
|
49
|
-
function(doc) {
|
|
52
|
+
function(doc) {
|
|
50
53
|
if (doc.chef_type == "cookbook_version") {
|
|
51
54
|
emit(doc.name, doc);
|
|
52
55
|
}
|
|
@@ -55,7 +58,7 @@ class Chef
|
|
|
55
58
|
},
|
|
56
59
|
"all_id" => {
|
|
57
60
|
"map" => <<-EOJS
|
|
58
|
-
function(doc) {
|
|
61
|
+
function(doc) {
|
|
59
62
|
if (doc.chef_type == "cookbook_version") {
|
|
60
63
|
emit(doc.name, doc.name);
|
|
61
64
|
}
|
|
@@ -64,7 +67,7 @@ class Chef
|
|
|
64
67
|
},
|
|
65
68
|
"all_with_version" => {
|
|
66
69
|
"map" => <<-EOJS
|
|
67
|
-
function(doc) {
|
|
70
|
+
function(doc) {
|
|
68
71
|
if (doc.chef_type == "cookbook_version") {
|
|
69
72
|
emit(doc.cookbook_name, doc.version);
|
|
70
73
|
}
|
|
@@ -73,7 +76,7 @@ class Chef
|
|
|
73
76
|
},
|
|
74
77
|
"all_latest_version" => {
|
|
75
78
|
"map" => %q@
|
|
76
|
-
function(doc) {
|
|
79
|
+
function(doc) {
|
|
77
80
|
if (doc.chef_type == "cookbook_version") {
|
|
78
81
|
emit(doc.cookbook_name, doc.version);
|
|
79
82
|
}
|
|
@@ -85,12 +88,12 @@ class Chef
|
|
|
85
88
|
|
|
86
89
|
for (var idx in values) {
|
|
87
90
|
var value = values[idx];
|
|
88
|
-
|
|
91
|
+
|
|
89
92
|
if (idx == 0) {
|
|
90
93
|
result = value;
|
|
91
94
|
continue;
|
|
92
95
|
}
|
|
93
|
-
|
|
96
|
+
|
|
94
97
|
var valueParts = value.split('.').map(function(v) { return parseInt(v); });
|
|
95
98
|
var resultParts = result.split('.').map(function(v) { return parseInt(v); });
|
|
96
99
|
|
|
@@ -187,7 +190,7 @@ class Chef
|
|
|
187
190
|
|
|
188
191
|
attr_reader :recipe_filenames_by_name
|
|
189
192
|
attr_reader :attribute_filenames_by_short_filename
|
|
190
|
-
|
|
193
|
+
|
|
191
194
|
# This is the one and only method that knows how cookbook files'
|
|
192
195
|
# checksums are generated.
|
|
193
196
|
def self.checksum_cookbook_file(filepath)
|
|
@@ -196,7 +199,7 @@ class Chef
|
|
|
196
199
|
Chef::Log.debug("File #{filepath} does not exist, so there is no checksum to generate")
|
|
197
200
|
nil
|
|
198
201
|
end
|
|
199
|
-
|
|
202
|
+
|
|
200
203
|
# Keep track of the filenames that we use in both eager cookbook
|
|
201
204
|
# downloading (during sync_cookbooks) and lazy (during the run
|
|
202
205
|
# itself, through FileVendor). After the run is over, clean up the
|
|
@@ -224,7 +227,8 @@ class Chef
|
|
|
224
227
|
# === Returns
|
|
225
228
|
# true:: Always returns true
|
|
226
229
|
def self.sync_cookbooks(cookbook_hash)
|
|
227
|
-
Chef::Log.
|
|
230
|
+
Chef::Log.info("Loading cookbooks [#{cookbook_hash.keys.sort.join(', ')}]")
|
|
231
|
+
Chef::Log.debug("Cookbooks detail: #{cookbook_hash.inspect}")
|
|
228
232
|
|
|
229
233
|
clear_obsoleted_cookbooks(cookbook_hash)
|
|
230
234
|
|
|
@@ -317,7 +321,7 @@ class Chef
|
|
|
317
321
|
# manifest.
|
|
318
322
|
cache.find(File.join(%w{cookbooks ** *})).each do |cache_filename|
|
|
319
323
|
unless valid_cache_entries[cache_filename]
|
|
320
|
-
Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer
|
|
324
|
+
Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer needed by chef-client.")
|
|
321
325
|
cache.delete(cache_filename)
|
|
322
326
|
end
|
|
323
327
|
end
|
|
@@ -329,12 +333,13 @@ class Chef
|
|
|
329
333
|
cleanup_file_cache
|
|
330
334
|
end
|
|
331
335
|
|
|
332
|
-
# Creates a new Chef::CookbookVersion object.
|
|
336
|
+
# Creates a new Chef::CookbookVersion object.
|
|
333
337
|
#
|
|
334
338
|
# === Returns
|
|
335
339
|
# object<Chef::CookbookVersion>:: Duh. :)
|
|
336
340
|
def initialize(name, couchdb=nil)
|
|
337
341
|
@name = name
|
|
342
|
+
@frozen = false
|
|
338
343
|
@attribute_filenames = Array.new
|
|
339
344
|
@definition_filenames = Array.new
|
|
340
345
|
@template_filenames = Array.new
|
|
@@ -359,7 +364,18 @@ class Chef
|
|
|
359
364
|
def version
|
|
360
365
|
metadata.version
|
|
361
366
|
end
|
|
362
|
-
|
|
367
|
+
|
|
368
|
+
# Indicates if this version is frozen or not. Freezing a coobkook version
|
|
369
|
+
# indicates that a new cookbook with the same name and version number
|
|
370
|
+
# shoule
|
|
371
|
+
def frozen_version?
|
|
372
|
+
@frozen
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def freeze_version
|
|
376
|
+
@frozen = true
|
|
377
|
+
end
|
|
378
|
+
|
|
363
379
|
def version=(new_version)
|
|
364
380
|
manifest["version"] = new_version
|
|
365
381
|
metadata.version(new_version)
|
|
@@ -375,7 +391,7 @@ class Chef
|
|
|
375
391
|
# :version = "1.0",
|
|
376
392
|
# :name = "Apache 2"
|
|
377
393
|
# :metadata = ???TODO: timh/cw: 5-24-2010: describe this format,
|
|
378
|
-
#
|
|
394
|
+
#
|
|
379
395
|
# :files => [
|
|
380
396
|
# {
|
|
381
397
|
# :name => "afile.rb",
|
|
@@ -393,7 +409,7 @@ class Chef
|
|
|
393
409
|
end
|
|
394
410
|
@manifest
|
|
395
411
|
end
|
|
396
|
-
|
|
412
|
+
|
|
397
413
|
def manifest=(new_manifest)
|
|
398
414
|
@manifest = Mash.new new_manifest
|
|
399
415
|
@checksums = extract_checksums_from_manifest(@manifest)
|
|
@@ -402,7 +418,7 @@ class Chef
|
|
|
402
418
|
COOKBOOK_SEGMENTS.each do |segment|
|
|
403
419
|
next unless @manifest.has_key?(segment)
|
|
404
420
|
filenames = @manifest[segment].map{|manifest_record| manifest_record['name']}
|
|
405
|
-
|
|
421
|
+
|
|
406
422
|
if segment == :recipes
|
|
407
423
|
self.recipe_filenames = filenames
|
|
408
424
|
elsif segment == :attributes
|
|
@@ -413,7 +429,7 @@ class Chef
|
|
|
413
429
|
end
|
|
414
430
|
end
|
|
415
431
|
end
|
|
416
|
-
|
|
432
|
+
|
|
417
433
|
# Returns a hash of checksums to either nil or the on disk path (which is
|
|
418
434
|
# done by generate_manifest).
|
|
419
435
|
def checksums
|
|
@@ -426,17 +442,17 @@ class Chef
|
|
|
426
442
|
def full_name
|
|
427
443
|
"#{name}-#{version}"
|
|
428
444
|
end
|
|
429
|
-
|
|
445
|
+
|
|
430
446
|
def attribute_filenames=(*filenames)
|
|
431
447
|
@attribute_filenames = filenames.flatten
|
|
432
448
|
@attribute_filenames_by_short_filename = filenames_by_name(attribute_filenames)
|
|
433
449
|
attribute_filenames
|
|
434
450
|
end
|
|
435
|
-
|
|
451
|
+
|
|
436
452
|
## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
|
|
437
453
|
alias :attribute_files :attribute_filenames
|
|
438
454
|
alias :attribute_files= :attribute_filenames=
|
|
439
|
-
|
|
455
|
+
|
|
440
456
|
# Return recipe names in the form of cookbook_name::recipe_name
|
|
441
457
|
def fully_qualified_recipe_names
|
|
442
458
|
results = Array.new
|
|
@@ -445,17 +461,17 @@ class Chef
|
|
|
445
461
|
end
|
|
446
462
|
results
|
|
447
463
|
end
|
|
448
|
-
|
|
464
|
+
|
|
449
465
|
def recipe_filenames=(*filenames)
|
|
450
466
|
@recipe_filenames = filenames.flatten
|
|
451
467
|
@recipe_filenames_by_name = filenames_by_name(recipe_filenames)
|
|
452
468
|
recipe_filenames
|
|
453
469
|
end
|
|
454
|
-
|
|
470
|
+
|
|
455
471
|
## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
|
|
456
472
|
alias :recipe_files :recipe_filenames
|
|
457
473
|
alias :recipe_files= :recipe_filenames=
|
|
458
|
-
|
|
474
|
+
|
|
459
475
|
# called from DSL
|
|
460
476
|
def load_recipe(recipe_name, run_context)
|
|
461
477
|
unless recipe_filenames_by_name.has_key?(recipe_name)
|
|
@@ -469,7 +485,7 @@ class Chef
|
|
|
469
485
|
unless recipe_filename
|
|
470
486
|
raise Chef::Exceptions::RecipeNotFound, "could not find recipe #{recipe_name} for cookbook #{name}"
|
|
471
487
|
end
|
|
472
|
-
|
|
488
|
+
|
|
473
489
|
recipe.from_file(recipe_filename)
|
|
474
490
|
recipe
|
|
475
491
|
end
|
|
@@ -519,7 +535,7 @@ class Chef
|
|
|
519
535
|
# ensure that we generate the manifest, which will also generate
|
|
520
536
|
# @manifest_records_by_path
|
|
521
537
|
manifest
|
|
522
|
-
|
|
538
|
+
|
|
523
539
|
# in order of prefernce, look for the filename in the manifest
|
|
524
540
|
found_pref = preferences.find {|preferred_filename| @manifest_records_by_path[preferred_filename] }
|
|
525
541
|
if found_pref
|
|
@@ -528,7 +544,7 @@ class Chef
|
|
|
528
544
|
raise Chef::Exceptions::FileNotFound, "cookbook #{name} does not contain file #{segment}/#{filename}"
|
|
529
545
|
end
|
|
530
546
|
end
|
|
531
|
-
|
|
547
|
+
|
|
532
548
|
def preferred_filename_on_disk_location(node, segment, filename, current_filepath=nil)
|
|
533
549
|
manifest_record = preferred_manifest_record(node, segment, filename)
|
|
534
550
|
if current_filepath && (manifest_record['checksum'] == self.class.checksum_cookbook_file(current_filepath))
|
|
@@ -594,7 +610,7 @@ class Chef
|
|
|
594
610
|
# preferences_for_path returns. It could be
|
|
595
611
|
# "files/ubuntu-9.10/dirname", for example.
|
|
596
612
|
specificity_dirname = $1
|
|
597
|
-
|
|
613
|
+
|
|
598
614
|
# Record the specificity_dirname only if it's in the list of
|
|
599
615
|
# valid preferences
|
|
600
616
|
if records_by_pref[specificity_dirname]
|
|
@@ -602,9 +618,9 @@ class Chef
|
|
|
602
618
|
end
|
|
603
619
|
end
|
|
604
620
|
end
|
|
605
|
-
|
|
621
|
+
|
|
606
622
|
best_pref = preferences.find { |pref| !records_by_pref[pref].empty? }
|
|
607
|
-
|
|
623
|
+
|
|
608
624
|
raise Chef::Exceptions::FileNotFound, "cookbook #{name} has no directory #{segment}/#{dirname}" unless best_pref
|
|
609
625
|
|
|
610
626
|
records_by_pref[best_pref]
|
|
@@ -628,7 +644,7 @@ class Chef
|
|
|
628
644
|
raise
|
|
629
645
|
end
|
|
630
646
|
end
|
|
631
|
-
|
|
647
|
+
|
|
632
648
|
fqdn = node[:fqdn]
|
|
633
649
|
|
|
634
650
|
# Most specific to least specific places to find the path
|
|
@@ -646,6 +662,7 @@ class Chef
|
|
|
646
662
|
|
|
647
663
|
def to_hash
|
|
648
664
|
result = manifest.dup
|
|
665
|
+
result['frozen?'] = frozen_version?
|
|
649
666
|
result['chef_type'] = 'cookbook_version'
|
|
650
667
|
result["_rev"] = couchdb_rev if couchdb_rev
|
|
651
668
|
result.to_hash
|
|
@@ -668,12 +685,17 @@ class Chef
|
|
|
668
685
|
cookbook_version.index_id = cookbook_version.couchdb_id
|
|
669
686
|
o.delete("_id")
|
|
670
687
|
end
|
|
671
|
-
cookbook_version.manifest = o
|
|
672
688
|
# We want the Chef::Cookbook::Metadata object to always be inflated
|
|
673
689
|
cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
|
|
690
|
+
cookbook_version.manifest = o
|
|
691
|
+
|
|
692
|
+
# We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>)
|
|
693
|
+
cookbook_version.manifest["metadata"] = JSON.parse(cookbook_version.metadata.to_json)
|
|
694
|
+
|
|
695
|
+
cookbook_version.freeze_version if o["frozen?"]
|
|
674
696
|
cookbook_version
|
|
675
697
|
end
|
|
676
|
-
|
|
698
|
+
|
|
677
699
|
def generate_manifest_with_urls(&url_generator)
|
|
678
700
|
rendered_manifest = manifest.dup
|
|
679
701
|
COOKBOOK_SEGMENTS.each do |segment|
|
|
@@ -712,12 +734,23 @@ class Chef
|
|
|
712
734
|
self.class.chef_server_rest
|
|
713
735
|
end
|
|
714
736
|
|
|
737
|
+
# Save this object to the server via the REST api. If there is an existing
|
|
738
|
+
# document on the server and it is marked frozen, a
|
|
739
|
+
# Net::HTTPServerException will be raised for 409 Conflict.
|
|
715
740
|
def save
|
|
716
741
|
chef_server_rest.put_rest("cookbooks/#{name}/#{version}", self)
|
|
717
742
|
self
|
|
718
743
|
end
|
|
719
744
|
alias :create :save
|
|
720
745
|
|
|
746
|
+
# Adds the `force=true` parameter to the upload. This allows the user to
|
|
747
|
+
# overwrite a frozen cookbook (normal #save raises a
|
|
748
|
+
# Net::HTTPServerException for 409 Conflict in this case).
|
|
749
|
+
def force_save
|
|
750
|
+
chef_server_rest.put_rest("cookbooks/#{name}/#{version}?force=true", self)
|
|
751
|
+
self
|
|
752
|
+
end
|
|
753
|
+
|
|
721
754
|
def destroy
|
|
722
755
|
chef_server_rest.delete_rest("cookbooks/#{name}/#{version}")
|
|
723
756
|
self
|
|
@@ -757,7 +790,7 @@ class Chef
|
|
|
757
790
|
##
|
|
758
791
|
# Couchdb
|
|
759
792
|
##
|
|
760
|
-
|
|
793
|
+
|
|
761
794
|
def self.cdb_by_name(cookbook_name, couchdb=nil)
|
|
762
795
|
cdb = (couchdb || Chef::CouchDB.new)
|
|
763
796
|
options = { :startkey => cookbook_name, :endkey => cookbook_name }
|
|
@@ -787,9 +820,13 @@ class Chef
|
|
|
787
820
|
end
|
|
788
821
|
|
|
789
822
|
def self.cdb_list(inflate=false, couchdb=nil)
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
823
|
+
couchdb ||= Chef::CouchDB.new
|
|
824
|
+
if inflate
|
|
825
|
+
couchdb.list("cookbooks", true)["rows"].collect{|r| r["value"]}
|
|
826
|
+
else
|
|
827
|
+
# If you modify this, please make sure the desc sorted order on the versions doesn't get broken.
|
|
828
|
+
couchdb.get_view("cookbooks", "all_with_version")["rows"].inject({}) { |mapped, row| mapped[row["key"]]||=Array.new; mapped[row["key"]].push(Chef::Version.new(row["value"])); mapped[row["key"]].sort!.reverse!; mapped}
|
|
829
|
+
end
|
|
793
830
|
end
|
|
794
831
|
|
|
795
832
|
def self.cdb_load(name, version='latest', couchdb=nil)
|
|
@@ -807,7 +844,7 @@ class Chef
|
|
|
807
844
|
end
|
|
808
845
|
|
|
809
846
|
# Runs on Chef Server (API); deletes the cookbook from couchdb and also destroys associated
|
|
810
|
-
# checksum documents
|
|
847
|
+
# checksum documents
|
|
811
848
|
def purge
|
|
812
849
|
checksums.keys.each do |checksum|
|
|
813
850
|
begin
|
|
@@ -827,8 +864,16 @@ class Chef
|
|
|
827
864
|
@index_id = value
|
|
828
865
|
end
|
|
829
866
|
|
|
867
|
+
def <=>(o)
|
|
868
|
+
raise Chef::Exceptions::CookbookVersionNameMismatch if self.name != o.name
|
|
869
|
+
# FIXME: can we change the interface to the Metadata class such
|
|
870
|
+
# that metadata.version returns a Chef::Version instance instead
|
|
871
|
+
# of a string?
|
|
872
|
+
Chef::Version.new(self.version) <=> Chef::Version.new(o.version)
|
|
873
|
+
end
|
|
874
|
+
|
|
830
875
|
private
|
|
831
|
-
|
|
876
|
+
|
|
832
877
|
# For each filename, produce a mapping of base filename (i.e. recipe name
|
|
833
878
|
# or attribute file) to on disk location
|
|
834
879
|
def filenames_by_name(filenames)
|
|
@@ -858,7 +903,7 @@ class Chef
|
|
|
858
903
|
file_name = nil
|
|
859
904
|
path = nil
|
|
860
905
|
specificity = "default"
|
|
861
|
-
|
|
906
|
+
|
|
862
907
|
if segment == :root_files
|
|
863
908
|
matcher = segment_file.match(".+/#{Regexp.escape(name.to_s)}/(.+)")
|
|
864
909
|
file_name = matcher[1]
|
|
@@ -877,7 +922,7 @@ class Chef
|
|
|
877
922
|
path = matcher[1]
|
|
878
923
|
file_name = matcher[2]
|
|
879
924
|
end
|
|
880
|
-
|
|
925
|
+
|
|
881
926
|
csum = self.class.checksum_cookbook_file(segment_file)
|
|
882
927
|
checksums_to_on_disk_paths[csum] = segment_file
|
|
883
928
|
rs = Mash.new({
|
|
@@ -900,7 +945,7 @@ class Chef
|
|
|
900
945
|
@manifest = manifest
|
|
901
946
|
@manifest_records_by_path = extract_manifest_records_by_path(manifest)
|
|
902
947
|
end
|
|
903
|
-
|
|
948
|
+
|
|
904
949
|
def file_vendor
|
|
905
950
|
unless @file_vendor
|
|
906
951
|
@file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest)
|
|
@@ -918,7 +963,7 @@ class Chef
|
|
|
918
963
|
end
|
|
919
964
|
checksums
|
|
920
965
|
end
|
|
921
|
-
|
|
966
|
+
|
|
922
967
|
def extract_manifest_records_by_path(manifest)
|
|
923
968
|
manifest_records_by_path = {}
|
|
924
969
|
COOKBOOK_SEGMENTS.each do |segment|
|
|
@@ -929,6 +974,6 @@ class Chef
|
|
|
929
974
|
end
|
|
930
975
|
manifest_records_by_path
|
|
931
976
|
end
|
|
932
|
-
|
|
977
|
+
|
|
933
978
|
end
|
|
934
979
|
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Tim Hinderliter (<tim@opscode.com>)
|
|
3
|
+
# Copyright:: Copyright (c) 2011 Opscode, Inc.
|
|
4
|
+
# License:: Apache License, Version 2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require 'dep_selector'
|
|
19
|
+
|
|
20
|
+
class Chef
|
|
21
|
+
module CookbookVersionSelector
|
|
22
|
+
# This method replaces verbiage from DepSelector messages with
|
|
23
|
+
# Chef-domain-specific verbiage, such as replacing package with
|
|
24
|
+
# cookbook.
|
|
25
|
+
#
|
|
26
|
+
# TODO [cw, 2011/2/25]: this is a near-term hack. In the long run,
|
|
27
|
+
# we'll do this better.
|
|
28
|
+
def self.filter_dep_selector_message(message)
|
|
29
|
+
m = message
|
|
30
|
+
m.gsub!("Package", "Cookbook")
|
|
31
|
+
m.gsub!("package", "cookbook")
|
|
32
|
+
m.gsub!("Solution constraint", "Run list item")
|
|
33
|
+
m.gsub!("solution constraint", "run list item")
|
|
34
|
+
m
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# all_cookbooks - a hash mapping cookbook names to an array of
|
|
38
|
+
# available CookbookVersions.
|
|
39
|
+
#
|
|
40
|
+
# Creates a DependencyGraph from CookbookVersion objects
|
|
41
|
+
def self.create_dependency_graph_from_cookbooks(all_cookbooks)
|
|
42
|
+
dep_graph = DepSelector::DependencyGraph.new
|
|
43
|
+
|
|
44
|
+
all_cookbooks.each do |cb_name, cb_versions|
|
|
45
|
+
cb_versions.each do |cb_version|
|
|
46
|
+
cb_version_deps = cb_version.metadata.dependencies
|
|
47
|
+
# TODO [cw. 2011/2/10]: CookbookVersion#version returns a
|
|
48
|
+
# String even though we're storing as a DepSelector::Version
|
|
49
|
+
# object underneath. This should be changed so that we
|
|
50
|
+
# return the object and handle proper serialization and
|
|
51
|
+
# de-serialization. For now, I'm just going to create a
|
|
52
|
+
# Version object from the String representation.
|
|
53
|
+
pv = dep_graph.package(cb_name).add_version(Chef::Version.new(cb_version.version))
|
|
54
|
+
cb_version_deps.each_pair do |dep_name, constraint_str|
|
|
55
|
+
# if the dependency is specified as cookbook::recipe,
|
|
56
|
+
# extract the cookbook component
|
|
57
|
+
dep_cb_name = dep_name.split("::").first
|
|
58
|
+
constraint = Chef::VersionConstraint.new(constraint_str)
|
|
59
|
+
pv.dependencies << DepSelector::Dependency.new(dep_graph.package(dep_cb_name), constraint)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
dep_graph
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Return a hash mapping cookbook names to a CookbookVersion
|
|
68
|
+
# object. If there is no solution that satisfies the constraints,
|
|
69
|
+
# the first run list item that caused unsatisfiability is
|
|
70
|
+
# returned.
|
|
71
|
+
#
|
|
72
|
+
# This is the final version-resolved list of cookbooks for the
|
|
73
|
+
# RunList.
|
|
74
|
+
#
|
|
75
|
+
# all_cookbooks - a hash mapping cookbook names to an array of
|
|
76
|
+
# available CookbookVersions.
|
|
77
|
+
#
|
|
78
|
+
# recipe_constraints - an array of hashes describing the expanded
|
|
79
|
+
# run list. Each element is a hash containing keys :name and
|
|
80
|
+
# :version_constraint. The :name component is either the
|
|
81
|
+
# fully-qualified recipe name (e.g. "cookbook1::non_default_recipe")
|
|
82
|
+
# or just a cookbook name, indicating the default recipe is to be
|
|
83
|
+
# run (e.g. "cookbook1").
|
|
84
|
+
def self.constrain(all_cookbooks, recipe_constraints)
|
|
85
|
+
dep_graph = create_dependency_graph_from_cookbooks(all_cookbooks)
|
|
86
|
+
|
|
87
|
+
# extract cookbook names from (possibly) fully-qualified recipe names
|
|
88
|
+
cookbook_constraints = recipe_constraints.map do |recipe_spec|
|
|
89
|
+
cookbook_name = (recipe_spec[:name][/^(.+)::/, 1] || recipe_spec[:name])
|
|
90
|
+
DepSelector::SolutionConstraint.new(dep_graph.package(cookbook_name),
|
|
91
|
+
recipe_spec[:version_constraint])
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Pass in the list of all available cookbooks (packages) so that
|
|
95
|
+
# DepSelector can distinguish between "no version available for
|
|
96
|
+
# cookbook X" and "no such cookbook X" when an environment
|
|
97
|
+
# filters out all versions for a given cookbook.
|
|
98
|
+
all_packages = all_cookbooks.inject([]) do |acc, (cookbook_name, cookbook_versions)|
|
|
99
|
+
acc << dep_graph.package(cookbook_name)
|
|
100
|
+
acc
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# find a valid assignment of CoookbookVersions. If no valid
|
|
104
|
+
# assignment exists, indicate which run_list_item causes the
|
|
105
|
+
# unsatisfiability and try to hint at what might be wrong.
|
|
106
|
+
soln =
|
|
107
|
+
begin
|
|
108
|
+
DepSelector::Selector.new(dep_graph).find_solution(cookbook_constraints, all_packages)
|
|
109
|
+
rescue DepSelector::Exceptions::InvalidSolutionConstraints => e
|
|
110
|
+
non_existent_cookbooks = e.non_existent_packages.map {|constraint| constraint.package.name}
|
|
111
|
+
cookbooks_with_no_matching_versions = e.constrained_to_no_versions.map {|constraint| constraint.package.name}
|
|
112
|
+
|
|
113
|
+
# Spend a whole lot of effort for pluralizing and
|
|
114
|
+
# prettifying the message.
|
|
115
|
+
message = ""
|
|
116
|
+
if non_existent_cookbooks.length > 0
|
|
117
|
+
message += "no such " + (non_existent_cookbooks.length > 1 ? "cookbooks" : "cookbook")
|
|
118
|
+
message += " #{non_existent_cookbooks.join(", ")}"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if cookbooks_with_no_matching_versions.length > 0
|
|
122
|
+
if message.length > 0
|
|
123
|
+
message += "; "
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
message += "no versions match the constraints on " + (cookbooks_with_no_matching_versions.length > 1 ? "cookbooks" : "cookbook")
|
|
127
|
+
message += " #{cookbooks_with_no_matching_versions.join(", ")}"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
message = "Run list contains invalid items: #{message}."
|
|
131
|
+
|
|
132
|
+
raise Chef::Exceptions::CookbookVersionSelection::InvalidRunListItems.new(message, non_existent_cookbooks, cookbooks_with_no_matching_versions)
|
|
133
|
+
rescue DepSelector::Exceptions::NoSolutionExists => e
|
|
134
|
+
raise Chef::Exceptions::CookbookVersionSelection::UnsatisfiableRunListItem.new(filter_dep_selector_message(e.message), e.unsatisfiable_solution_constraint, e.disabled_non_existent_packages, e.disabled_most_constrained_packages)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# map assignment back to CookbookVersion objects
|
|
139
|
+
selected_cookbooks = {}
|
|
140
|
+
soln.each_pair do |cb_name, cb_version|
|
|
141
|
+
# TODO [cw, 2011/2/10]: related to the TODO in
|
|
142
|
+
# create_dependency_graph_from_cookbooks, cbv.version
|
|
143
|
+
# currently returns a String, so we must compare to
|
|
144
|
+
# cb_version.to_s, since it's a for-real Version object.
|
|
145
|
+
selected_cookbooks[cb_name] = all_cookbooks[cb_name].find{|cbv| cbv.version == cb_version.to_s}
|
|
146
|
+
end
|
|
147
|
+
selected_cookbooks
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Expands the run_list, constrained to the environment's CookbookVersion
|
|
151
|
+
# constraints.
|
|
152
|
+
#
|
|
153
|
+
# Returns:
|
|
154
|
+
# Hash of: name to CookbookVersion
|
|
155
|
+
def self.expand_to_cookbook_versions(run_list, environment, couchdb=nil)
|
|
156
|
+
# expand any roles in this run_list.
|
|
157
|
+
expanded_run_list = run_list.expand(environment, 'couchdb', :couchdb => couchdb).recipes.with_version_constraints
|
|
158
|
+
|
|
159
|
+
cookbooks_for_environment = Chef::Environment.cdb_load_filtered_cookbook_versions(environment, couchdb)
|
|
160
|
+
constrain(cookbooks_for_environment, expanded_run_list)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|