summaryrefslogtreecommitdiff
path: root/lib/chef
diff options
context:
space:
mode:
authorThom May <thom@chef.io>2017-03-21 10:31:40 +0000
committerThom May <thom@chef.io>2017-04-04 07:18:09 +0100
commit8f62f18a24e3213ef4b2f13a5abf0135bf6c2429 (patch)
tree7e3073c1b9a7aeb1fd54b08a191ad3bfcf0674f0 /lib/chef
parente3b9e67a880bcd658517f90a6add837c0e026798 (diff)
downloadchef-8f62f18a24e3213ef4b2f13a5abf0135bf6c2429.tar.gz
RFC 67: Remove cookbook segments
This implements RFC 67, which removes cookbook segments, and moves to a single list of all the files contained in a cookbook. This allows us to move forward with better audit modes and also proper shipping of ohai plugins. Signed-off-by: Thom May <thom@chef.io>
Diffstat (limited to 'lib/chef')
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb4
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb8
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb39
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb6
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb6
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb7
-rw-r--r--lib/chef/cookbook/cookbook_version_loader.rb85
-rw-r--r--lib/chef/cookbook/file_system_file_vendor.rb2
-rw-r--r--lib/chef/cookbook/manifest_v0.rb63
-rw-r--r--lib/chef/cookbook/manifest_v2.rb41
-rw-r--r--lib/chef/cookbook/remote_file_vendor.rb6
-rw-r--r--lib/chef/cookbook/synchronizer.rb45
-rw-r--r--lib/chef/cookbook_manifest.rb156
-rw-r--r--lib/chef/cookbook_site_streaming_uploader.rb16
-rw-r--r--lib/chef/cookbook_uploader.rb2
-rw-r--r--lib/chef/cookbook_version.rb202
-rw-r--r--lib/chef/http/socketless_chef_zero_client.rb1
-rw-r--r--lib/chef/knife/cookbook_download.rb7
-rw-r--r--lib/chef/knife/cookbook_show.rb10
-rw-r--r--lib/chef/policy_builder/expand_node_object.rb3
-rw-r--r--lib/chef/policy_builder/policyfile.rb13
-rw-r--r--lib/chef/run_context/cookbook_compiler.rb2
22 files changed, 340 insertions, 384 deletions
diff --git a/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb
index 5030a0733f..63ce71ef40 100644
--- a/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb
@@ -103,11 +103,11 @@ class Chef
end
def get_json(path)
- Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :api_version => "0").get(path)
+ chef_rest.get(path)
end
def chef_rest
- Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key)
+ Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :api_version => "0")
end
def api_path
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb
index 0b82a64a0a..e4df7858a7 100644
--- a/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb
@@ -56,7 +56,7 @@ class Chef
# to make this work. So instead, we make a temporary cookbook
# symlinking back to real cookbook, and upload the proxy.
def upload_cookbook(other, options)
- cookbook_name, dash, identifier = other.name.rpartition("-")
+ cookbook_name, _, identifier = other.name.rpartition("-")
Dir.mktmpdir do |temp_cookbooks_path|
proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
@@ -73,7 +73,7 @@ class Chef
cookbook_to_upload.freeze_version if options[:freeze]
# Instantiate a new uploader based on the proxy loader
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, force: options[:force], rest: root.chef_rest, policy_mode: true)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, force: options[:force], rest: chef_rest, policy_mode: true)
with_actual_cookbooks_dir(temp_cookbooks_path) do
uploader.upload_cookbooks
@@ -92,6 +92,10 @@ class Chef
end
end
+ def chef_rest
+ Chef::ServerAPI.new(root.chef_rest.url, root.chef_rest.options.merge(version_class: Chef::CookbookManifestVersions))
+ end
+
def can_have_child?(name, is_dir)
is_dir && name.include?("-")
end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb
index 8f5faf2183..64488ed705 100644
--- a/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb
@@ -49,18 +49,6 @@ class Chef
attr_reader :cookbook_name, :version
- COOKBOOK_SEGMENT_INFO = {
- :attributes => { :ruby_only => true },
- :definitions => { :ruby_only => true },
- :recipes => { :ruby_only => true },
- :libraries => { :recursive => true },
- :templates => { :recursive => true },
- :files => { :recursive => true },
- :resources => { :ruby_only => true, :recursive => true },
- :providers => { :ruby_only => true, :recursive => true },
- :root_files => {},
- }
-
def add_child(child)
@children << child
end
@@ -80,34 +68,29 @@ class Chef
end
def can_have_child?(name, is_dir)
- # A cookbook's root may not have directories unless they are segment directories
- return name != "root_files" && COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) if is_dir
+ return name != "root_files" if is_dir
true
end
def children
if @children.nil?
@children = []
- manifest = chef_object.manifest
- COOKBOOK_SEGMENT_INFO.each do |segment, segment_info|
- next unless manifest.has_key?(segment)
-
- # Go through each file in the manifest for the segment, and
- # add cookbook subdirs and files for it.
- manifest[segment].each do |segment_file|
- parts = segment_file[:path].split("/")
+ manifest = chef_object.cookbook_manifest
+ manifest.by_parent_directory.each do |segment, files|
+ files.each do |file|
+ parts = file[:path].split("/")
# Get or create the path to the file
container = self
parts[0, parts.length - 1].each do |part|
old_container = container
container = old_container.children.find { |child| part == child.name }
if !container
- container = CookbookSubdir.new(part, old_container, segment_info[:ruby_only], segment_info[:recursive])
+ container = CookbookSubdir.new(part, old_container, false, true)
old_container.add_child(container)
end
end
# Create the file itself
- container.add_child(CookbookFile.new(parts[parts.length - 1], container, segment_file))
+ container.add_child(CookbookFile.new(parts[parts.length - 1], container, file))
end
end
@children = @children.sort_by { |c| c.name }
@@ -165,7 +148,11 @@ class Chef
end
def rest
- parent.rest
+ Chef::ServerAPI.new(parent.rest.url, parent.rest.options.merge(version_class: Chef::CookbookManifestVersions))
+ end
+
+ def chef_rest
+ Chef::ServerAPI.new(parent.chef_rest.url, parent.chef_rest.options.merge(version_class: Chef::CookbookManifestVersions))
end
def chef_object
@@ -187,7 +174,7 @@ class Chef
old_retry_count = Chef::Config[:http_retry_count]
begin
Chef::Config[:http_retry_count] = 0
- @chef_object ||= Chef::CookbookVersion.from_hash(root.get_json(api_path))
+ @chef_object ||= Chef::CookbookVersion.from_hash(chef_rest.get(api_path))
ensure
Chef::Config[:http_retry_count] = old_retry_count
end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb
index 631562d7ef..4e8e68e364 100644
--- a/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb
@@ -74,13 +74,17 @@ class Chef
def upload_cookbook(other, options)
cookbook_to_upload = other.chef_object
cookbook_to_upload.freeze_version if options[:freeze]
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => chef_rest)
with_actual_cookbooks_dir(other.parent.file_path) do
uploader.upload_cookbooks
end
end
+ def chef_rest
+ Chef::ServerAPI.new(root.chef_rest.url, root.chef_rest.options.merge(version_class: Chef::CookbookManifestVersions))
+ end
+
# Work around the fact that CookbookUploader doesn't understand chef_repo_path (yet)
def with_actual_cookbooks_dir(actual_cookbook_path)
old_cookbook_path = Chef::Config.cookbook_path
diff --git a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb
index 172405763a..8da3718136 100644
--- a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb
@@ -78,7 +78,7 @@ class Chef
cookbook_to_upload.freeze_version if options[:freeze]
# Instantiate a new uploader based on the proxy loader
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => chef_rest)
with_actual_cookbooks_dir(temp_cookbooks_path) do
uploader.upload_cookbooks
@@ -97,6 +97,10 @@ class Chef
end
end
+ def chef_rest
+ Chef::ServerAPI.new(root.chef_rest.url, root.chef_rest.options.merge(version_class: Chef::CookbookManifestVersions))
+ end
+
def can_have_child?(name, is_dir)
is_dir && name =~ Chef::ChefFS::FileSystem::ChefServer::VersionedCookbookDir::VALID_VERSIONED_COOKBOOK_NAME
end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb
index 31b538b9ce..b296901dd1 100644
--- a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb
@@ -97,9 +97,9 @@ class Chef
end
def can_have_child?(name, is_dir)
- if is_dir
+ if is_dir && !%w{ root_files .. . }.include?(name)
# Only the given directories will be uploaded.
- return Chef::ChefFS::FileSystem::ChefServer::CookbookDir::COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) && name != "root_files"
+ return true
elsif name == Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE
return false
end
@@ -128,8 +128,7 @@ class Chef
protected
def make_child_entry(child_name)
- segment_info = Chef::ChefFS::FileSystem::ChefServer::CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {}
- ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive])
+ ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, false, true)
end
def cookbook_version
diff --git a/lib/chef/cookbook/cookbook_version_loader.rb b/lib/chef/cookbook/cookbook_version_loader.rb
index b9de9a7482..35dac27fa5 100644
--- a/lib/chef/cookbook/cookbook_version_loader.rb
+++ b/lib/chef/cookbook/cookbook_version_loader.rb
@@ -9,15 +9,6 @@ class Chef
class Cookbook
class CookbookVersionLoader
- FILETYPES_SUBJECT_TO_IGNORE = [ :attribute_filenames,
- :definition_filenames,
- :recipe_filenames,
- :template_filenames,
- :file_filenames,
- :library_filenames,
- :resource_filenames,
- :provider_filenames]
-
UPLOADED_COOKBOOK_VERSION_FILE = ".uploaded-cookbook-version.json".freeze
attr_reader :cookbook_settings
@@ -44,16 +35,7 @@ class Chef
@relative_path = /#{Regexp.escape(@cookbook_path)}\/(.+)$/
@metadata_loaded = false
@cookbook_settings = {
- :all_files => {},
- :attribute_filenames => {},
- :definition_filenames => {},
- :recipe_filenames => {},
- :template_filenames => {},
- :file_filenames => {},
- :library_filenames => {},
- :resource_filenames => {},
- :provider_filenames => {},
- :root_filenames => {},
+ :all_files => {},
}
@metadata_filenames = []
@@ -84,16 +66,6 @@ class Chef
remove_ignored_files
- load_as(:attribute_filenames, "attributes", "*.rb")
- load_as(:definition_filenames, "definitions", "*.rb")
- load_as(:recipe_filenames, "recipes", "*.rb")
- load_recursively_as(:library_filenames, "libraries", "*")
- load_recursively_as(:template_filenames, "templates", "*")
- load_recursively_as(:file_filenames, "files", "*")
- load_recursively_as(:resource_filenames, "resources", "*.rb")
- load_recursively_as(:provider_filenames, "providers", "*.rb")
- load_root_files
-
if empty?
Chef::Log.warn "Found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping."
end
@@ -126,16 +98,6 @@ class Chef
Chef::CookbookVersion.new(cookbook_name, *cookbook_paths).tap do |c|
c.all_files = cookbook_settings[:all_files].values
- c.attribute_filenames = cookbook_settings[:attribute_filenames].values
- c.definition_filenames = cookbook_settings[:definition_filenames].values
- c.recipe_filenames = cookbook_settings[:recipe_filenames].values
- c.template_filenames = cookbook_settings[:template_filenames].values
- c.file_filenames = cookbook_settings[:file_filenames].values
- c.library_filenames = cookbook_settings[:library_filenames].values
- c.resource_filenames = cookbook_settings[:resource_filenames].values
- c.provider_filenames = cookbook_settings[:provider_filenames].values
- c.root_filenames = cookbook_settings[:root_filenames].values
- c.metadata_filenames = metadata_filenames
c.metadata = metadata
c.freeze_version if @frozen
@@ -253,51 +215,6 @@ class Chef
end
end
- def load_root_files
- select_files_by_glob(File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), "*"), File::FNM_DOTMATCH).each do |file|
- file = Chef::Util::PathHelper.cleanpath(file)
- next if File.directory?(file)
- next if File.basename(file) == UPLOADED_COOKBOOK_VERSION_FILE
- name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file)
- cookbook_settings[:root_filenames][name] = file
- end
- end
-
- def load_recursively_as(category, category_dir, glob)
- glob_pattern = File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path, category_dir), "**", glob)
- select_files_by_glob(glob_pattern, File::FNM_DOTMATCH).each do |file|
- file = Chef::Util::PathHelper.cleanpath(file)
- name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file)
- cookbook_settings[category][name] = file
- end
- end
-
- def load_as(category, *path_glob)
- glob_pattern = File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), *path_glob)
- select_files_by_glob(glob_pattern).each do |file|
- file = Chef::Util::PathHelper.cleanpath(file)
- name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file)
- cookbook_settings[category][name] = file
- end
- end
-
- # Mimic Dir.glob inside a cookbook by running `File.fnmatch?` against
- # `cookbook_settings[:all_files]`.
- #
- # @param pattern [String] a glob string passed to `File.fnmatch?`
- # @param option [Integer] Option flag to control globbing behavior. These
- # are constants defined on `File`, such as `File::FNM_DOTMATCH`.
- # `File.fnmatch?` and `Dir.glob` only take one option argument, if you
- # need to combine options, you must `|` the constants together. To make
- # `File.fnmatch?` behave like `Dir.glob`, `File::FNM_PATHNAME` is
- # always enabled.
- def select_files_by_glob(pattern, option = 0)
- combined_opts = option | File::FNM_PATHNAME
- cookbook_settings[:all_files].values.select do |path|
- File.fnmatch?(pattern, path, combined_opts)
- end
- end
-
def remove_ignored_files
cookbook_settings[:all_files].reject! do |relative_path, full_path|
chefignore.ignored?(relative_path)
diff --git a/lib/chef/cookbook/file_system_file_vendor.rb b/lib/chef/cookbook/file_system_file_vendor.rb
index 8088ed00cd..1f43095ea3 100644
--- a/lib/chef/cookbook/file_system_file_vendor.rb
+++ b/lib/chef/cookbook/file_system_file_vendor.rb
@@ -35,7 +35,7 @@ class Chef
attr_reader :repo_paths
def initialize(manifest, *repo_paths)
- @cookbook_name = manifest[:cookbook_name]
+ @cookbook_name = manifest.name
@repo_paths = repo_paths.flatten
raise ArgumentError, "You must specify at least one repo path" if repo_paths.empty?
end
diff --git a/lib/chef/cookbook/manifest_v0.rb b/lib/chef/cookbook/manifest_v0.rb
new file mode 100644
index 0000000000..3e50d86071
--- /dev/null
+++ b/lib/chef/cookbook/manifest_v0.rb
@@ -0,0 +1,63 @@
+# Author:: Daniel DeLeo (<dan@chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "chef/json_compat"
+require "chef/mixin/versioned_api"
+
+class Chef
+ class Cookbook
+ class ManifestV0
+ extend Chef::Mixin::VersionedAPI
+
+ minimum_api_version 0
+
+ COOKBOOK_SEGMENTS = %w{ resources providers recipes definitions libraries attributes files templates root_files }
+
+ def self.from_hash(hash)
+ response = Mash.new
+ response[:all_files] = COOKBOOK_SEGMENTS.inject([]) do |memo, segment|
+ next memo if hash[segment].nil? || hash[segment].empty?
+ hash[segment].each do |file|
+ file["name"] = "#{segment}/#{file["name"]}" unless segment == "root_files"
+ memo << file
+ end
+ memo
+ end
+ response
+ end
+
+ def self.to_hash(manifest)
+ result = manifest.manifest.dup
+ result.delete("all_files")
+
+ files = manifest.by_parent_directory
+ files.keys.inject(result) do |memo, parent|
+ if COOKBOOK_SEGMENTS.include?(parent)
+ memo[parent] ||= []
+ files[parent].each do |file|
+ file["name"] = file["name"].split("/")[1] unless parent == "root_files"
+ file.delete("full_path")
+ memo[parent] << file
+ end
+ end
+ memo
+ end
+
+ result.merge({ "frozen?" => manifest.frozen_version?, "chef_type" => "cookbook_version" })
+ end
+ end
+ end
+end
diff --git a/lib/chef/cookbook/manifest_v2.rb b/lib/chef/cookbook/manifest_v2.rb
new file mode 100644
index 0000000000..59b5c9afb0
--- /dev/null
+++ b/lib/chef/cookbook/manifest_v2.rb
@@ -0,0 +1,41 @@
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "chef/json_compat"
+require "chef/mixin/versioned_api"
+
+class Chef
+ class Cookbook
+ class ManifestV2
+ extend Chef::Mixin::VersionedAPI
+
+ minimum_api_version 2
+
+ def self.from_hash(hash)
+ Chef::Log.debug "processing manifest: #{hash}"
+ Mash.new hash
+ end
+
+ def self.to_hash(manifest)
+ result = manifest.manifest.dup
+ result["all_files"].map! { |file| file.delete("full_path"); file }
+ result["frozen?"] = manifest.frozen_version?
+ result["chef_type"] = "cookbook_version"
+ result.to_hash
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/cookbook/remote_file_vendor.rb b/lib/chef/cookbook/remote_file_vendor.rb
index e63d094dc4..cfd7789311 100644
--- a/lib/chef/cookbook/remote_file_vendor.rb
+++ b/lib/chef/cookbook/remote_file_vendor.rb
@@ -30,7 +30,7 @@ class Chef
def initialize(manifest, rest)
@manifest = manifest
- @cookbook_name = @manifest[:cookbook_name] || @manifest[:name]
+ @cookbook_name = @manifest.name
@rest = rest
end
@@ -44,8 +44,8 @@ class Chef
raise "get_filename: Cannot determine segment/filename for incoming filename #{filename}"
end
- raise "No such segment #{segment} in cookbook #{@cookbook_name}" unless @manifest[segment]
- found_manifest_record = @manifest[segment].find { |manifest_record| manifest_record[:path] == filename }
+ raise "No such segment #{segment} in cookbook #{@cookbook_name}" unless @manifest.files_for(segment)
+ found_manifest_record = @manifest.files_for(segment).find { |manifest_record| manifest_record[:path] == filename }
raise "No such file #{filename} in #{@cookbook_name}" unless found_manifest_record
cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record["path"])
diff --git a/lib/chef/cookbook/synchronizer.rb b/lib/chef/cookbook/synchronizer.rb
index bb44bc3d5c..625f3b4f20 100644
--- a/lib/chef/cookbook/synchronizer.rb
+++ b/lib/chef/cookbook/synchronizer.rb
@@ -62,18 +62,11 @@ class Chef
# Synchronizes the locally cached copies of cookbooks with the files on the
# server.
class CookbookSynchronizer
- CookbookFile = Struct.new(:cookbook, :segment, :manifest_record)
+ CookbookFile = Struct.new(:cookbook, :manifest_record)
attr_accessor :remove_obsoleted_files
def initialize(cookbooks_by_name, events)
- @eager_segments = Chef::CookbookVersion::COOKBOOK_SEGMENTS.dup
- unless Chef::Config[:no_lazy_load]
- @eager_segments.delete(:files)
- @eager_segments.delete(:templates)
- end
- @eager_segments.freeze
-
@cookbooks_by_name, @events = cookbooks_by_name, events
@cookbook_full_file_paths = {}
@@ -101,15 +94,19 @@ class Chef
end
def cookbook_segment(cookbook_name, segment)
- @cookbooks_by_name[cookbook_name].manifest[segment]
+ @cookbooks_by_name[cookbook_name].files_for(segment)
end
def files
+ exclude = unless Chef::Config[:no_lazy_load]
+ [ :files, :templates ]
+ else
+ []
+ end
+
@files ||= cookbooks.inject([]) do |memo, cookbook|
- @eager_segments.each do |segment|
- cookbook.manifest[segment].each do |manifest_record|
- memo << CookbookFile.new(cookbook, segment, manifest_record)
- end
+ cookbook.each_file(excluded_parts: exclude) do |manifest_record|
+ memo << CookbookFile.new(cookbook, manifest_record)
end
memo
end
@@ -162,8 +159,10 @@ class Chef
@events.cookbook_sync_start(cookbook_count)
queue.process(Chef::Config[:cookbook_sync_threads])
+ # Ensure that cookbooks know where they're rooted at, for manifest purposes.
+ ensure_cookbook_paths
# Update the full file paths in the manifest
- update_cookbook_filenames()
+ update_cookbook_filenames
rescue Exception => e
@events.cookbook_sync_failed(cookbooks, e)
@@ -176,9 +175,8 @@ class Chef
# Saves the full_path to the file of the cookbook to be updated
# in the manifest later
def save_full_file_path(file, full_path)
- @cookbook_full_file_paths[file.cookbook] ||= {}
- @cookbook_full_file_paths[file.cookbook][file.segment] ||= [ ]
- @cookbook_full_file_paths[file.cookbook][file.segment] << full_path
+ @cookbook_full_file_paths[file.cookbook] ||= []
+ @cookbook_full_file_paths[file.cookbook] << full_path
end
# remove cookbooks that are not referenced in the expanded run_list at all
@@ -229,10 +227,15 @@ class Chef
end
def update_cookbook_filenames
- @cookbook_full_file_paths.each do |cookbook, file_segments|
- file_segments.each do |segment, full_paths|
- cookbook.replace_segment_filenames(segment, full_paths)
- end
+ @cookbook_full_file_paths.each do |cookbook, full_paths|
+ cookbook.all_files = full_paths
+ end
+ end
+
+ def ensure_cookbook_paths
+ cookbooks.each do |cookbook|
+ cb_dir = File.join(Chef::Config[:file_cache_path], "cookbooks", cookbook.name)
+ cookbook.root_paths = Array(cb_dir)
end
end
diff --git a/lib/chef/cookbook_manifest.rb b/lib/chef/cookbook_manifest.rb
index d6de9dd029..125f353d21 100644
--- a/lib/chef/cookbook_manifest.rb
+++ b/lib/chef/cookbook_manifest.rb
@@ -15,7 +15,10 @@
# limitations under the License.
require "forwardable"
+require "chef/mixin/versioned_api"
require "chef/util/path_helper"
+require "chef/cookbook/manifest_v0"
+require "chef/cookbook/manifest_v2"
require "chef/log"
class Chef
@@ -24,17 +27,11 @@ class Chef
# to a Chef Server.
class CookbookManifest
- # Duplicates the same constant in CookbookVersion. We cannot remove it
- # there because it is treated by other code as part of CookbookVersion's
- # public API (also used in some deprecated methods).
- COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ].freeze
-
extend Forwardable
attr_reader :cookbook_version
def_delegator :@cookbook_version, :root_paths
- def_delegator :@cookbook_version, :segment_filenames
def_delegator :@cookbook_version, :name
def_delegator :@cookbook_version, :identifier
def_delegator :@cookbook_version, :metadata
@@ -56,10 +53,7 @@ class Chef
# the format used by the `cookbook_artifacts` endpoint (for policyfiles).
# Setting this option also changes the behavior of #save_url and
# #force_save_url such that CookbookVersions will be uploaded to the new
- # `cookbook_artifacts` API. This endpoint is currently under active
- # development and the format is expected to change frequently, therefore
- # the result of #manifest, #to_hash, and #to_json will not be stable when
- # `policy_mode` is enabled.
+ # `cookbook_artifacts` API.
def initialize(cookbook_version, policy_mode: false)
@cookbook_version = cookbook_version
@policy_mode = !!policy_mode
@@ -126,10 +120,7 @@ class Chef
end
def to_hash
- result = manifest.dup
- result["frozen?"] = frozen_version?
- result["chef_type"] = "cookbook_version"
- result.to_hash
+ CookbookManifestVersions.to_hash(self)
end
def to_json(*a)
@@ -164,15 +155,48 @@ class Chef
# make the corresponding changes to the cookbook_version object. Required
# to provide backward compatibility with CookbookVersion#manifest= method.
def update_from(new_manifest)
- @manifest = Mash.new new_manifest
+ @manifest = Chef::CookbookManifestVersions.from_hash(new_manifest)
@checksums = extract_checksums_from_manifest(@manifest)
@manifest_records_by_path = extract_manifest_records_by_path(@manifest)
+ end
+
+ def files_for(part)
+ return root_files if part.to_s == "root_files"
+ manifest[:all_files].select do |file|
+ seg = file[:name].split("/")[0]
+ part.to_s == seg
+ end
+ end
+
+ def each_file(excluded_parts: [], &block)
+ excluded_parts = Array(excluded_parts).map { |p| p.to_s }
- COOKBOOK_SEGMENTS.each do |segment|
- next unless @manifest.has_key?(segment)
- filenames = @manifest[segment].map { |manifest_record| manifest_record["name"] }
+ manifest[:all_files].each do |file|
+ seg = file[:name].split("/")[0]
+ next if excluded_parts.include?(seg)
+ yield file if block_given?
+ end
+ end
+
+ def by_parent_directory
+ @by_parent_directory ||=
+ manifest[:all_files].inject({}) do |memo, file|
+ parts = file[:name].split("/")
+ parent = if parts.length == 1
+ "root_files"
+ else
+ parts[0]
+ end
+
+ memo[parent] ||= []
+ memo[parent] << file
+ memo
+ end
+ end
- cookbook_version.replace_segment_filenames(segment, filenames)
+ def root_files
+ manifest[:all_files].select do |file|
+ file[:name].split("/").length == 1
end
end
@@ -186,15 +210,7 @@ class Chef
# See #preferred_manifest_record for a description an individual manifest record.
def generate_manifest
manifest = Mash.new({
- :recipes => Array.new,
- :definitions => Array.new,
- :libraries => Array.new,
- :attributes => Array.new,
- :files => Array.new,
- :templates => Array.new,
- :resources => Array.new,
- :providers => Array.new,
- :root_files => Array.new,
+ all_files: Array.new,
})
@checksums = {}
@@ -203,24 +219,24 @@ class Chef
raise "Cookbook #{name} does not have root_paths! Cannot generate manifest."
end
- COOKBOOK_SEGMENTS.each do |segment|
- segment_filenames(segment).each do |segment_file|
- next if File.directory?(segment_file)
+ @cookbook_version.all_files.each do |file|
+ next if File.directory?(file)
- path, specificity = parse_segment_file_from_root_paths(segment, segment_file)
- file_name = File.basename(path)
+ name, path, specificity = parse_file_from_root_paths(file)
- csum = checksum_cookbook_file(segment_file)
- @checksums[csum] = segment_file
- rs = Mash.new({
- :name => file_name,
- :path => path,
- :checksum => csum,
- :specificity => specificity,
- })
+ csum = checksum_cookbook_file(file)
+ @checksums[csum] = file
+ rs = Mash.new({
+ :name => name,
+ :path => path,
+ :checksum => csum,
+ :specificity => specificity,
+ # full_path is not a part of the normal manifest, but is very useful to keep around.
+ # uploaders should strip this out.
+ :full_path => file,
+ })
- manifest[segment] << rs
- end
+ manifest[:all_files] << rs
end
manifest[:metadata] = metadata
@@ -238,38 +254,42 @@ class Chef
@manifest = manifest
end
- def parse_segment_file_from_root_paths(segment, segment_file)
+ def parse_file_from_root_paths(file)
root_paths.each do |root_path|
- pathname = Chef::Util::PathHelper.relative_path_from(root_path, segment_file)
+ pathname = Chef::Util::PathHelper.relative_path_from(root_path, file)
parts = pathname.each_filename.take(2)
# Check if path is actually under root_path
next if parts[0] == ".."
- if segment == :templates || segment == :files
+
+ # if we have a root_file, such as metadata.rb, the first part will be "."
+ return [ pathname.to_s, pathname.to_s, "default" ] if parts.length == 1
+
+ segment = parts[0]
+
+ name = File.join(segment, pathname.basename.to_s)
+
+ if segment == "templates" || segment == "files"
# Check if pathname looks like files/foo or templates/foo (unscoped)
if pathname.each_filename.to_a.length == 2
# Use root_default in case the same path exists at root_default and default
- return [ pathname.to_s, "root_default" ]
+ return [ name, pathname.to_s, "root_default" ]
else
- return [ pathname.to_s, parts[1] ]
+ return [ name, pathname.to_s, parts[1] ]
end
else
- return [ pathname.to_s, "default" ]
+ return [ name, pathname.to_s, "default" ]
end
end
- Chef::Log.error("Cookbook file #{segment_file} not under cookbook root paths #{root_paths.inspect}.")
- raise "Cookbook file #{segment_file} not under cookbook root paths #{root_paths.inspect}."
+ Chef::Log.error("Cookbook file #{file} not under cookbook root paths #{root_paths.inspect}.")
+ raise "Cookbook file #{file} not under cookbook root paths #{root_paths.inspect}."
end
def extract_checksums_from_manifest(manifest)
- checksums = {}
- COOKBOOK_SEGMENTS.each do |segment|
- next unless manifest.has_key?(segment)
- manifest[segment].each do |manifest_record|
- checksums[manifest_record[:checksum]] = nil
- end
+ manifest[:all_files].inject({}) do |memo, manifest_record|
+ memo[manifest_record[:checksum]] = nil
+ memo
end
- checksums
end
def checksum_cookbook_file(filepath)
@@ -277,14 +297,20 @@ class Chef
end
def extract_manifest_records_by_path(manifest)
- manifest_records_by_path = {}
- COOKBOOK_SEGMENTS.each do |segment|
- next unless manifest.has_key?(segment)
- manifest[segment].each do |manifest_record|
- manifest_records_by_path[manifest_record[:path]] = manifest_record
- end
+ manifest[:all_files].inject({}) do |memo, manifest_record|
+ memo[manifest_record[:path]] = manifest_record
+ memo
end
- manifest_records_by_path
end
+
+ end
+ class CookbookManifestVersions
+
+ extend Chef::Mixin::VersionedAPIFactory
+ add_versioned_api_class Chef::Cookbook::ManifestV0
+ add_versioned_api_class Chef::Cookbook::ManifestV2
+
+ def_versioned_delegator :from_hash
+ def_versioned_delegator :to_hash
end
end
diff --git a/lib/chef/cookbook_site_streaming_uploader.rb b/lib/chef/cookbook_site_streaming_uploader.rb
index c0e85ff984..1641992eac 100644
--- a/lib/chef/cookbook_site_streaming_uploader.rb
+++ b/lib/chef/cookbook_site_streaming_uploader.rb
@@ -43,15 +43,13 @@ class Chef
FileUtils.mkdir_p(tmp_cookbook_dir)
Chef::Log.debug("Staging at #{tmp_cookbook_dir}")
checksums_to_on_disk_paths = cookbook.checksums
- Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
- cookbook.manifest[segment].each do |manifest_record|
- path_in_cookbook = manifest_record[:path]
- on_disk_path = checksums_to_on_disk_paths[manifest_record[:checksum]]
- dest = File.join(tmp_cookbook_dir, cookbook.name.to_s, path_in_cookbook)
- FileUtils.mkdir_p(File.dirname(dest))
- Chef::Log.debug("Staging #{on_disk_path} to #{dest}")
- FileUtils.cp(on_disk_path, dest)
- end
+ cookbook.each_file do |manifest_record|
+ path_in_cookbook = manifest_record[:path]
+ on_disk_path = checksums_to_on_disk_paths[manifest_record[:checksum]]
+ dest = File.join(tmp_cookbook_dir, cookbook.name.to_s, path_in_cookbook)
+ FileUtils.mkdir_p(File.dirname(dest))
+ Chef::Log.debug("Staging #{on_disk_path} to #{dest}")
+ FileUtils.cp(on_disk_path, dest)
end
# First, generate metadata
diff --git a/lib/chef/cookbook_uploader.rb b/lib/chef/cookbook_uploader.rb
index bb75234563..5e11314190 100644
--- a/lib/chef/cookbook_uploader.rb
+++ b/lib/chef/cookbook_uploader.rb
@@ -40,7 +40,7 @@ class Chef
def initialize(cookbooks, opts = {})
@opts = opts
@cookbooks = Array(cookbooks)
- @rest = opts[:rest] || Chef::ServerAPI.new(Chef::Config[:chef_server_url])
+ @rest = opts[:rest] || Chef::ServerAPI.new(Chef::Config[:chef_server_url], version_class: Chef::CookbookManifestVersions)
@concurrency = opts[:concurrency] || 10
@policy_mode = opts[:policy_mode] || false
end
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 7353941bb1..738f98929e 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -37,45 +37,23 @@ class Chef
class CookbookVersion
include Comparable
+ extend Forwardable
+
+ def_delegator :@cookbook_manifest, :files_for
+ def_delegator :@cookbook_manifest, :each_file
COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
- attr_accessor :all_files
+ attr_reader :all_files
attr_accessor :root_paths
- attr_accessor :definition_filenames
- attr_accessor :template_filenames
- attr_accessor :file_filenames
- attr_accessor :library_filenames
- attr_accessor :resource_filenames
- attr_accessor :provider_filenames
- attr_accessor :root_filenames
attr_accessor :name
- attr_accessor :metadata_filenames
-
- def status=(new_status)
- Chef.deprecated(:internal_api, "Deprecated method `status' called. This method will be removed.")
- @status = new_status
- end
-
- def status
- Chef.deprecated(:internal_api, "Deprecated method `status' called. This method will be removed.")
- @status
- end
# A Chef::Cookbook::Metadata object. It has a setter that fixes up the
# metadata to add descriptions of the recipes contained in this
# CookbookVersion.
attr_reader :metadata
- # attribute_filenames also has a setter that has non-default
- # functionality.
- attr_reader :attribute_filenames
-
- # recipe_filenames also has a setter that has non-default
- # functionality.
- attr_reader :recipe_filenames
-
attr_reader :recipe_filenames_by_name
attr_reader :attribute_filenames_by_short_filename
@@ -96,6 +74,11 @@ class Chef
root_paths[0]
end
+ def all_files=(files)
+ @all_files = Array(files)
+ cookbook_manifest.reset!
+ end
+
# This is the one and only method that knows how cookbook files'
# checksums are generated.
def self.checksum_cookbook_file(filepath)
@@ -118,23 +101,10 @@ class Chef
@root_paths = root_paths
@frozen = false
- @attribute_filenames = Array.new
- @definition_filenames = Array.new
- @template_filenames = Array.new
- @file_filenames = Array.new
- @recipe_filenames = Array.new
- @recipe_filenames_by_name = Hash.new
- @library_filenames = Array.new
- @resource_filenames = Array.new
- @provider_filenames = Array.new
- @metadata_filenames = Array.new
- @root_filenames = Array.new
-
@all_files = Array.new
- # deprecated
- @status = :ready
@file_vendor = nil
+ @cookbook_manifest = Chef::CookbookManifest.new(self)
@metadata = Chef::Cookbook::Metadata.new
@chef_server_rest = chef_server_rest
end
@@ -163,10 +133,12 @@ class Chef
"#{name}-#{version}"
end
- def attribute_filenames=(*filenames)
- @attribute_filenames = filenames.flatten
- @attribute_filenames_by_short_filename = filenames_by_name(attribute_filenames)
- attribute_filenames
+ def attribute_filenames_by_short_filename
+ @attribute_filenames_by_short_filename ||= filenames_by_name(files_for("attributes"))
+ end
+
+ def recipe_filenames_by_name
+ @recipe_filenames_by_name ||= filenames_by_name(files_for("recipes"))
end
def metadata=(metadata)
@@ -175,14 +147,14 @@ class Chef
@metadata
end
- ## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
- alias :attribute_files :attribute_filenames
- alias :attribute_files= :attribute_filenames=
-
def manifest
cookbook_manifest.manifest
end
+ def manifest=(new_manifest)
+ cookbook_manifest.update_from(new_manifest)
+ end
+
# Returns a hash of checksums to either nil or the on disk path (which is
# done by generate_manifest).
def checksums
@@ -193,29 +165,16 @@ class Chef
cookbook_manifest.manifest_records_by_path
end
- def manifest=(new_manifest)
- cookbook_manifest.update_from(new_manifest)
- end
-
# Return recipe names in the form of cookbook_name::recipe_name
def fully_qualified_recipe_names
- results = Array.new
- recipe_filenames_by_name.each_key do |rname|
- results << "#{name}::#{rname}"
+ files_for("recipes").inject([]) do |memo, recipe|
+ rname = recipe[:name].split("/")[1]
+ rname = File.basename(rname, ".rb")
+ memo << "#{name}::#{rname}"
+ memo
end
- results
end
- def recipe_filenames=(*filenames)
- @recipe_filenames = filenames.flatten
- @recipe_filenames_by_name = filenames_by_name(recipe_filenames)
- recipe_filenames
- end
-
- ## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
- alias :recipe_files :recipe_filenames
- alias :recipe_files= :recipe_filenames=
-
# called from DSL
def load_recipe(recipe_name, run_context)
unless recipe_filenames_by_name.has_key?(recipe_name)
@@ -235,41 +194,7 @@ class Chef
end
def segment_filenames(segment)
- unless COOKBOOK_SEGMENTS.include?(segment)
- raise ArgumentError, "invalid segment #{segment}: must be one of #{COOKBOOK_SEGMENTS.join(', ')}"
- end
-
- case segment.to_sym
- when :resources
- @resource_filenames
- when :providers
- @provider_filenames
- when :recipes
- @recipe_filenames
- when :libraries
- @library_filenames
- when :definitions
- @definition_filenames
- when :attributes
- @attribute_filenames
- when :files
- @file_filenames
- when :templates
- @template_filenames
- when :root_files
- @root_filenames
- end
- end
-
- def replace_segment_filenames(segment, filenames)
- case segment.to_sym
- when :recipes
- self.recipe_filenames = filenames
- when :attributes
- self.attribute_filenames = filenames
- else
- segment_filenames(segment).replace(filenames)
- end
+ files_for(segment).map { |f| f["full_path"] || File.join(root_dir, f["path"]) }
end
# Query whether a template file +template_filename+ is available. File
@@ -349,7 +274,7 @@ class Chef
filenames_by_pref = Hash.new
preferences.each { |pref| filenames_by_pref[pref] = Array.new }
- manifest[segment].each do |manifest_record|
+ files_for(segment).each do |manifest_record|
manifest_record_path = manifest_record[:path]
# find the NON SPECIFIC filenames, but prefer them by filespecificity.
@@ -389,7 +314,7 @@ class Chef
records_by_pref = Hash.new
preferences.each { |pref| records_by_pref[pref] = Array.new }
- manifest[segment].each do |manifest_record|
+ files_for(segment).each do |manifest_record|
manifest_record_path = manifest_record[:path]
# extract the preference part from the path.
@@ -469,12 +394,22 @@ class Chef
end
private :preferences_for_path
+ def display
+ output = Mash.new
+ output["cookbook_name"] = name
+ output["name"] = full_name
+ output["frozen?"] = frozen_version?
+ output["metadata"] = metadata.to_hash
+ output["version"] = version
+ output.merge(cookbook_manifest.by_parent_directory)
+ end
+
def self.from_hash(o)
cookbook_version = new(o["cookbook_name"] || o["name"])
# We want the Chef::Cookbook::Metadata object to always be inflated
- cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
cookbook_version.manifest = o
+ cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
cookbook_version.identifier = o["identifier"] if o.key?("identifier")
# We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>)
@@ -488,33 +423,6 @@ class Chef
from_hash(o)
end
- # @deprecated This method was used by the Ruby Chef Server and is no longer
- # needed. There is no replacement.
- def generate_manifest_with_urls
- Chef.deprecated(:internal_api, "Deprecated method #generate_manifest_with_urls.")
-
- rendered_manifest = manifest.dup
- COOKBOOK_SEGMENTS.each do |segment|
- if rendered_manifest.has_key?(segment)
- rendered_manifest[segment].each do |manifest_record|
- url_options = { :cookbook_name => name.to_s, :cookbook_version => version, :checksum => manifest_record["checksum"] }
- manifest_record["url"] = yield(url_options)
- end
- end
- end
- rendered_manifest
- end
-
- def to_hash
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.to_hash
- end
-
- def to_json(*a)
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.to_json
- end
-
def metadata_json_file
File.join(root_paths[0], "metadata.json")
end
@@ -533,22 +441,12 @@ class Chef
# REST API
##
- def save_url
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.save_url
- end
-
- def force_save_url
- # TODO: this should become deprecated when the API for CookbookManifest becomes stable
- cookbook_manifest.force_save_url
- end
-
def chef_server_rest
@chef_server_rest ||= chef_server_rest
end
def self.chef_server_rest
- Chef::ServerAPI.new(Chef::Config[:chef_server_url])
+ Chef::ServerAPI.new(Chef::Config[:chef_server_url], { version_class: Chef::CookbookManifestVersions })
end
def destroy
@@ -602,12 +500,12 @@ class Chef
Chef::Version.new(version) <=> Chef::Version.new(other.version)
end
- private
-
def cookbook_manifest
@cookbook_manifest ||= CookbookManifest.new(self)
end
+ private
+
def find_preferred_manifest_record(node, segment, filename)
preferences = preferences_for_path(node, segment, filename)
@@ -615,15 +513,21 @@ class Chef
preferences.find { |preferred_filename| manifest_records_by_path[preferred_filename] }
end
- # For each filename, produce a mapping of base filename (i.e. recipe name
+ # For each manifest record, produce a mapping of base filename (i.e. recipe name
+ # or attribute file) to on disk location
+ def relative_paths_by_name(records)
+ records.select { |record| record[:name] =~ /\.rb$/ }.inject({}) { |memo, record| memo[File.basename(record[:name], ".rb")] = record[:path]; memo }
+ end
+
+ # For each manifest record, produce a mapping of base filename (i.e. recipe name
# or attribute file) to on disk location
- def filenames_by_name(filenames)
- filenames.select { |filename| filename =~ /\.rb$/ }.inject({}) { |memo, filename| memo[File.basename(filename, ".rb")] = filename; memo }
+ def filenames_by_name(records)
+ records.select { |record| record[:name] =~ /\.rb$/ }.inject({}) { |memo, record| memo[File.basename(record[:name], ".rb")] = record[:full_path]; memo }
end
def file_vendor
unless @file_vendor
- @file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest)
+ @file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(cookbook_manifest)
end
@file_vendor
end
diff --git a/lib/chef/http/socketless_chef_zero_client.rb b/lib/chef/http/socketless_chef_zero_client.rb
index d2f1f45b1d..296330815a 100644
--- a/lib/chef/http/socketless_chef_zero_client.rb
+++ b/lib/chef/http/socketless_chef_zero_client.rb
@@ -170,6 +170,7 @@ class Chef
"QUERY_STRING" => url.query,
"SERVER_PORT" => url.port,
"HTTP_HOST" => "localhost:#{url.port}",
+ "HTTP_X_OPS_SERVER_API_VERSION" => headers["X-Ops-Server-API-Version"],
"rack.url_scheme" => "chefzero",
"rack.input" => StringIO.new(body_str),
}
diff --git a/lib/chef/knife/cookbook_download.rb b/lib/chef/knife/cookbook_download.rb
index 741f444093..b745e77f27 100644
--- a/lib/chef/knife/cookbook_download.rb
+++ b/lib/chef/knife/cookbook_download.rb
@@ -70,7 +70,7 @@ class Chef
ui.info("Downloading #{@cookbook_name} cookbook version #{@version}")
cookbook = Chef::CookbookVersion.load(@cookbook_name, @version)
- manifest = cookbook.manifest
+ manifest = cookbook.cookbook_manifest
basedir = File.join(config[:download_directory], "#{@cookbook_name}-#{cookbook.version}")
if File.exists?(basedir)
@@ -83,10 +83,9 @@ class Chef
end
end
- Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
- next unless manifest.has_key?(segment)
+ manifest.by_parent_directory.each do |segment, files|
ui.info("Downloading #{segment}")
- manifest[segment].each do |segment_file|
+ files.each do |segment_file|
dest = File.join(basedir, segment_file["path"].gsub("/", File::SEPARATOR))
Chef::Log.debug("Downloading #{segment_file['path']} to #{dest}")
FileUtils.mkdir_p(File.dirname(dest))
diff --git a/lib/chef/knife/cookbook_show.rb b/lib/chef/knife/cookbook_show.rb
index d0c930de0a..1d9983632d 100644
--- a/lib/chef/knife/cookbook_show.rb
+++ b/lib/chef/knife/cookbook_show.rb
@@ -76,9 +76,13 @@ class Chef
pretty_print(temp_file.read)
when 3 # We are showing a specific part of the cookbook
- output(cookbook.manifest[segment])
- when 2 # We are showing the whole cookbook data
- output(cookbook)
+ if segment == "metadata"
+ output(cookbook.metadata)
+ else
+ output(cookbook.files_for(segment))
+ end
+ when 2 # We are showing the whole cookbook
+ output(cookbook.display)
when 1 # We are showing the cookbook versions (all of them)
env = config[:environment]
api_endpoint = env ? "environments/#{env}/cookbooks/#{cookbook_name}" : "cookbooks/#{cookbook_name}"
diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb
index dbed44a002..26f39e8b73 100644
--- a/lib/chef/policy_builder/expand_node_object.rb
+++ b/lib/chef/policy_builder/expand_node_object.rb
@@ -239,7 +239,8 @@ class Chef
end
def api_service
- @api_service ||= Chef::ServerAPI.new(config[:chef_server_url])
+ @api_service ||= Chef::ServerAPI.new(config[:chef_server_url],
+ { version_class: Chef::CookbookManifestVersions })
end
def config
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index f0009eac6c..f84e1dc68e 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -149,7 +149,7 @@ class Chef
#
# @return [Chef::RunContext]
def setup_run_context(specific_recipes = nil)
- Chef::Cookbook::FileVendor.fetch_from_remote(http_api)
+ Chef::Cookbook::FileVendor.fetch_from_remote(api_service)
sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync)
cookbook_collection.validate!
@@ -267,7 +267,7 @@ class Chef
# @api private
def policy
- @policy ||= http_api.get(policyfile_location)
+ @policy ||= api_service.get(policyfile_location)
rescue Net::HTTPServerException => e
raise ConfigurationError, "Error loading policyfile from `#{policyfile_location}': #{e.class} - #{e.message}"
end
@@ -452,8 +452,9 @@ class Chef
end
# @api private
- def http_api
- @api_service ||= Chef::ServerAPI.new(config[:chef_server_url])
+ def api_service
+ @api_service ||= Chef::ServerAPI.new(config[:chef_server_url],
+ { version_class: Chef::CookbookManifestVersions })
end
# @api private
@@ -496,7 +497,7 @@ class Chef
def compat_mode_manifest_for(cookbook_name, lock_data)
xyz_version = lock_data["dotted_decimal_identifier"]
rel_url = "cookbooks/#{cookbook_name}/#{xyz_version}"
- inflate_cbv_object(http_api.get(rel_url))
+ inflate_cbv_object(api_service.get(rel_url))
rescue Exception => e
message = "Error loading cookbook #{cookbook_name} at version #{xyz_version} from #{rel_url}: #{e.class} - #{e.message}"
err = Chef::Exceptions::CookbookNotFound.new(message)
@@ -507,7 +508,7 @@ class Chef
def artifact_manifest_for(cookbook_name, lock_data)
identifier = lock_data["identifier"]
rel_url = "cookbook_artifacts/#{cookbook_name}/#{identifier}"
- inflate_cbv_object(http_api.get(rel_url))
+ inflate_cbv_object(api_service.get(rel_url))
rescue Exception => e
message = "Error loading cookbook #{cookbook_name} with identifier #{identifier} from #{rel_url}: #{e.class} - #{e.message}"
err = Chef::Exceptions::CookbookNotFound.new(message)
diff --git a/lib/chef/run_context/cookbook_compiler.rb b/lib/chef/run_context/cookbook_compiler.rb
index b2a8d236a3..94635be03d 100644
--- a/lib/chef/run_context/cookbook_compiler.rb
+++ b/lib/chef/run_context/cookbook_compiler.rb
@@ -268,7 +268,7 @@ class Chef
# Lists the local paths to files in +cookbook+ of type +segment+
# (attribute, recipe, etc.), sorted lexically.
def files_in_cookbook_by_segment(cookbook, segment)
- cookbook_collection[cookbook].segment_filenames(segment).sort
+ cookbook_collection[cookbook].files_for(segment).map { |record| record[:full_path] }.sort
end
# Yields the name, as a symbol, of each cookbook depended on by