From c57862350cdd62a03e7be0b6752129b8fc533fc8 Mon Sep 17 00:00:00 2001 From: Thom May Date: Fri, 6 Jan 2017 16:53:09 +0000 Subject: Remove cookbook segments This implements RFC 67, Cookbook Segment Deprecation, for the default backend of Chef Zero. It also does a little bit of work to make API versions more ergonomic. Signed-off-by: Thom May --- lib/chef_zero/chef_data/cookbook_data.rb | 68 ++++++++++++------------------ lib/chef_zero/chef_data/data_normalizer.rb | 50 +++++++++++++++++++--- 2 files changed, 69 insertions(+), 49 deletions(-) (limited to 'lib/chef_zero/chef_data') diff --git a/lib/chef_zero/chef_data/cookbook_data.rb b/lib/chef_zero/chef_data/cookbook_data.rb index bdad333..2766162 100644 --- a/lib/chef_zero/chef_data/cookbook_data.rb +++ b/lib/chef_zero/chef_data/cookbook_data.rb @@ -13,7 +13,9 @@ module ChefZero end result = files_from(cookbook) - recipe_names = result[:recipes].map do |recipe| + recipe_names = result[:all_files].select do |file| + file[:name].start_with?("recipes/") + end.map do |recipe| recipe_name = recipe[:name][0..-2] recipe_name == "default" ? name : "#{name}::#{recipe_name}" end @@ -86,26 +88,10 @@ module ChefZero cookbook_arg(:supports, cookbook, version_constraints) end - def recommends(cookbook, *version_constraints) - cookbook_arg(:recommendations, cookbook, version_constraints) - end - - def suggests(cookbook, *version_constraints) - cookbook_arg(:suggestions, cookbook, version_constraints) - end - - def conflicts(cookbook, *version_constraints) - cookbook_arg(:conflicting, cookbook, version_constraints) - end - def provides(cookbook, *version_constraints) cookbook_arg(:providing, cookbook, version_constraints) end - def replaces(cookbook, *version_constraints) - cookbook_arg(:replacing, cookbook, version_constraints) - end - def gem(*opts) self[:gems] ||= [] self[:gems] << opts @@ -119,10 +105,6 @@ module ChefZero self[:attributes][name] = options end - def grouping(name, options) - self[:grouping][name] = options - end - def cookbook_arg(key, cookbook, version_constraints) self[key][cookbook] = version_constraints.first || ">= 0.0.0" end @@ -142,19 +124,14 @@ module ChefZero def self.files_from(directory) # TODO some support .rb only + result = load_files(directory) + + set_specificity(result, :templates) + set_specificity(result, :files) + result = { - :attributes => load_child_files(directory, "attributes", false), - :definitions => load_child_files(directory, "definitions", false), - :recipes => load_child_files(directory, "recipes", false), - :libraries => load_child_files(directory, "libraries", true), - :templates => load_child_files(directory, "templates", true), - :files => load_child_files(directory, "files", true), - :resources => load_child_files(directory, "resources", true), - :providers => load_child_files(directory, "providers", true), - :root_files => load_files(directory, false), + all_files: result, } - set_specificity(result[:templates]) - set_specificity(result[:files]) result end @@ -199,45 +176,52 @@ module ChefZero end end - def self.load_child_files(parent, key, recursive) - result = load_files(get_directory(parent, key), recursive) + def self.load_child_files(parent, key, recursive, part) + result = load_files(get_directory(parent, key), recursive, part) result.each do |file| file[:path] = "#{key}/#{file[:path]}" end result end - def self.load_files(directory, recursive) + def self.load_files(directory, recursive = true, part = nil) result = [] if directory list(directory).each do |child_name| dir = get_directory(directory, child_name) if dir + child_part = child_name if part.nil? if recursive - result += load_child_files(directory, child_name, recursive) + result += load_child_files(directory, child_name, recursive, child_part) end else - result += load_file(read_file(directory, child_name), child_name) + result += load_file(read_file(directory, child_name), child_name, part) end end end result end - def self.load_file(value, name) + def self.load_file(value, name, part = nil) + specific_name = part ? "#{part}/#{name}" : name [{ - :name => name, + :name => specific_name, :path => name, :checksum => Digest::MD5.hexdigest(value), :specificity => "default", }] end - def self.set_specificity(files) + def self.set_specificity(files, type) files.each do |file| + next unless file[:name].split("/")[0] == type.to_s + parts = file[:path].split("/") - raise "Only directories are allowed directly under templates or files: #{file[:path]}" if parts.size == 2 - file[:specificity] = parts[1] + file[:specificity] = if parts.size == 2 + "default" + else + parts[1] + end end end end diff --git a/lib/chef_zero/chef_data/data_normalizer.rb b/lib/chef_zero/chef_data/data_normalizer.rb index 939acc5..6e96f85 100644 --- a/lib/chef_zero/chef_data/data_normalizer.rb +++ b/lib/chef_zero/chef_data/data_normalizer.rb @@ -5,6 +5,9 @@ require "chef_zero/chef_data/default_creator" module ChefZero module ChefData class DataNormalizer + + COOKBOOK_SEGMENTS = %w{ resources providers recipes definitions libraries attributes files templates root_files } + def self.normalize_acls(acls) ChefData::DefaultCreator::PERMISSIONS.each do |perm| acls[perm] ||= {} @@ -90,18 +93,51 @@ module ChefZero end def self.normalize_cookbook(endpoint, org_prefix, cookbook, name, version, base_uri, method, - is_cookbook_artifact = false) + is_cookbook_artifact = false, api_version: 2) # TODO I feel dirty - if method != "PUT" - cookbook.each_pair do |key, value| - if value.is_a?(Array) - value.each do |file| - if file.is_a?(Hash) && file.has_key?("checksum") - file["url"] ||= endpoint.build_uri(base_uri, org_prefix + ["file_store", "checksums", file["checksum"]]) + if method == "PUT" && api_version < 2 + cookbook["all_files"] = cookbook.delete(["root_files"]) { [] } + COOKBOOK_SEGMENTS.each do |segment| + next unless cookbook.has_key? segment + cookbook[segment].each do |file| + file["name"] = "#{segment}/#{file['name']}" + cookbook["all_files"] << file + end + cookbook.delete(segment) + end + elsif method != "PUT" + if cookbook.key? "all_files" + cookbook["all_files"].each do |file| + if file.is_a?(Hash) && file.has_key?("checksum") + file["url"] ||= endpoint.build_uri(base_uri, org_prefix + ["file_store", "checksums", file["checksum"]]) + end + end + + # down convert to old style manifest, ensuring we don't send all_files on the wire and that we correctly divine segments + # any file that's not in an old segment is just dropped on the floor. + if api_version < 2 + + # the spec appears to think we should send empty arrays for each segment, so let's do that + COOKBOOK_SEGMENTS.each { |seg| cookbook[seg] ||= [] } + + cookbook["all_files"].each do |file| + segment, name = file["name"].split("/") + + # root_files have no segment prepended + if name.nil? + name = segment + segment = "root_files" end + + file.delete("full_path") + next unless COOKBOOK_SEGMENTS.include? segment + file["name"] = name + cookbook[segment] << file end + cookbook.delete("all_files") end end + cookbook["name"] ||= "#{name}-#{version}" # TODO it feels wrong, but the real chef server doesn't expand 'version', so we don't either. -- cgit v1.2.1