diff options
Diffstat (limited to 'lib/chef/cookbook_version.rb')
-rw-r--r-- | lib/chef/cookbook_version.rb | 244 |
1 files changed, 75 insertions, 169 deletions
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb index 1e903608b5..7bb3f3385f 100644 --- a/lib/chef/cookbook_version.rb +++ b/lib/chef/cookbook_version.rb @@ -4,7 +4,7 @@ # Author:: Tim Hinderliter (<tim@chef.io>) # Author:: Seth Falcon (<seth@chef.io>) # Author:: Daniel DeLeo (<dan@chef.io>) -# Copyright:: Copyright 2008-2016, Chef Software, Inc. +# Copyright:: Copyright 2008-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,50 +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.log_deprecation("Deprecated method `status' called. This method will be removed.") - @status = new_status - end - - def status - Chef.log_deprecation("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 - - attr_accessor :chef_server_rest - # The `identifier` field is used for cookbook_artifacts, which are # organized on the chef server according to their content. If the # policy_mode option to CookbookManifest is set to true it will include @@ -96,12 +69,17 @@ 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) Chef::Digester.generate_md5_checksum_for_file(filepath) rescue Errno::ENOENT - Chef::Log.debug("File #{filepath} does not exist, so there is no checksum to generate") + Chef::Log.trace("File #{filepath} does not exist, so there is no checksum to generate") nil end @@ -118,23 +96,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,26 +128,40 @@ 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 ||= begin + name_map = filenames_by_name(files_for("attributes")) + root_alias = cookbook_manifest.root_files.find { |record| record[:name] == "attributes.rb" } + name_map["default"] = root_alias[:full_path] if root_alias + name_map + end + end + + def recipe_filenames_by_name + @recipe_filenames_by_name ||= begin + name_map = filenames_by_name(files_for("recipes")) + root_alias = cookbook_manifest.root_files.find { |record| record[:name] == "recipe.rb" } + if root_alias + Chef::Log.error("Cookbook #{name} contains both recipe.rb and and recipes/default.rb, ignoring recipes/default.rb") if name_map["default"] + name_map["default"] = root_alias[:full_path] + end + name_map + end end def metadata=(metadata) @metadata = metadata @metadata.recipes_from_cookbook_version(self) - @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,36 +172,23 @@ 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) raise Chef::Exceptions::RecipeNotFound, "could not find recipe #{recipe_name} for cookbook #{name}" end - Chef::Log.debug("Found recipe #{recipe_name} in cookbook #{name}") + Chef::Log.trace("Found recipe #{recipe_name} in cookbook #{name}") recipe = Chef::Recipe.new(name, recipe_name, run_context) recipe_filename = recipe_filenames_by_name[recipe_name] @@ -235,41 +201,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 @@ -316,13 +248,13 @@ class Chef error_message << error_locations.join("\n") existing_files = segment_filenames(segment) # Strip the root_dir prefix off all files for readability - pretty_existing_files = existing_files.map { |path| + pretty_existing_files = existing_files.map do |path| if root_dir path[root_dir.length + 1..-1] else path end - } + end # Show the files that the cookbook does have. If the user made a typo, # hopefully they'll see it here. unless pretty_existing_files.empty? @@ -349,7 +281,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 +321,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 +401,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. <<, >>) @@ -484,42 +426,10 @@ class Chef cookbook_version end - def self.json_create(o) - Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::CookbookVersion#from_hash") - from_hash(o) - end - def self.from_cb_artifact_data(o) 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.log_deprecation("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 @@ -538,22 +448,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 ||= self.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 @@ -599,20 +499,20 @@ class Chef end end - def <=>(o) - raise Chef::Exceptions::CookbookVersionNameMismatch if self.name != o.name + def <=>(other) + raise Chef::Exceptions::CookbookVersionNameMismatch if name != other.name # FIXME: can we change the interface to the Metadata class such # that metadata.version returns a Chef::Version instance instead # of a string? - Chef::Version.new(self.version) <=> Chef::Version.new(o.version) + 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) @@ -620,15 +520,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 |