diff options
23 files changed, 483 insertions, 479 deletions
diff --git a/lib/chef_zero/chef_data/cookbook_data.rb b/lib/chef_zero/chef_data/cookbook_data.rb new file mode 100644 index 0000000..48b99bf --- /dev/null +++ b/lib/chef_zero/chef_data/cookbook_data.rb @@ -0,0 +1,238 @@ +require 'digest/md5' +require 'hashie/mash' + +module ChefZero + module ChefData + module CookbookData + def self.to_hash(cookbook, name, version=nil) + frozen = false + if cookbook.has_key?(:frozen) + frozen = cookbook[:frozen] + cookbook = cookbook.dup + cookbook.delete(:frozen) + end + + result = files_from(cookbook) + recipe_names = result[:recipes].map do |recipe| + recipe_name = recipe[:name][0..-2] + recipe_name == 'default' ? name : "#{name}::#{recipe_name}" + end + result[:metadata] = metadata_from(cookbook, name, version, recipe_names) + result[:name] = "#{name}-#{result[:metadata][:version]}" + result[:json_class] = 'Chef::CookbookVersion' + result[:cookbook_name] = name + result[:version] = result[:metadata][:version] + result[:chef_type] = 'cookbook_version' + result[:frozen?] = true if frozen + result + end + + def self.metadata_from(directory, name, version, recipe_names) + metadata = PretendCookbookMetadata.new(PretendCookbook.new(name, recipe_names)) + # If both .rb and .json exist, read .rb + # TODO if recipes has 3 recipes in it, and the Ruby/JSON has only one, should + # the resulting recipe list have 1, or 3-4 recipes in it? + if has_child(directory, 'metadata.rb') + begin + file = filename(directory, 'metadata.rb') || "(#{name}/metadata.rb)" + metadata.instance_eval(read_file(directory, 'metadata.rb'), file) + rescue + ChefZero::Log.error("Error loading cookbook #{name}: #{$!}\n #{$!.backtrace.join("\n ")}") + end + elsif has_child(directory, 'metadata.json') + metadata.from_json(read_file(directory, 'metadata.json')) + end + result = {} + metadata.to_hash.each_pair do |key,value| + result[key.to_sym] = value + end + result[:version] = version if version + result + end + + private + + # Just enough cookbook to make a Metadata object + class PretendCookbook + def initialize(name, fully_qualified_recipe_names) + @name = name + @fully_qualified_recipe_names = fully_qualified_recipe_names + end + attr_reader :name, :fully_qualified_recipe_names + end + + # Handles loading configuration values from a Chef config file + # + # @author Justin Campbell <justin.campbell@riotgames.com> + class PretendCookbookMetadata < Hash + # @param [String] path + def initialize(cookbook) + self.name(cookbook.name) + self.recipes(cookbook.fully_qualified_recipe_names) + %w(attributes grouping dependencies supports recommendations suggestions conflicting providing replacing recipes).each do |hash_arg| + self[hash_arg.to_sym] = Hashie::Mash.new + end + end + + def from_json(json) + self.merge!(JSON.parse(json)) + end + + private + + def depends(cookbook, *version_constraints) + cookbook_arg(:dependencies, cookbook, version_constraints) + end + + def supports(cookbook, *version_constraints) + 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 recipe(recipe, description) + self[:recipes][recipe] = description + end + + def attribute(name, options) + 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 + + def method_missing(key, value = nil) + if value.nil? + self[key.to_sym] + else + store key.to_sym, value + end + end + end + + def self.files_from(directory) + # TODO some support .rb only + 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', false), + :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) + } + set_specificity(result[:templates]) + set_specificity(result[:files]) + result + end + + def self.has_child(directory, name) + if directory.is_a?(Hash) + directory.has_key?(name) + else + directory.child(name).exists? + end + end + + def self.read_file(directory, name) + if directory.is_a?(Hash) + directory[name] + else + directory.child(name).read + end + end + + def self.filename(directory, name) + if directory.respond_to?(:file_path) + File.join(directory.file_path, name) + else + nil + end + end + + def self.get_directory(directory, name) + if directory.is_a?(Hash) + directory[name].is_a?(Hash) ? directory[name] : nil + else + result = directory.child(name) + result.dir? ? result : nil + end + end + + def self.list(directory) + if directory.is_a?(Hash) + directory.keys + else + directory.children.map { |c| c.name } + end + end + + def self.load_child_files(parent, key, recursive) + result = load_files(get_directory(parent, key), recursive) + result.each do |file| + file[:path] = "#{key}/#{file[:path]}" + end + result + end + + def self.load_files(directory, recursive) + result = [] + if directory + list(directory).each do |child_name| + dir = get_directory(directory, child_name) + if dir + if recursive + result += load_child_files(directory, child_name, recursive) + end + else + result += load_file(read_file(directory, child_name), child_name) + end + end + end + result + end + + def self.load_file(value, name) + [{ + :name => name, + :path => name, + :checksum => Digest::MD5.hexdigest(value), + :specificity => 'default' + }] + end + + def self.set_specificity(files) + files.each do |file| + parts = file[:path].split('/') + raise "Only directories are allowed directly under templates or files: #{file[:path]}" if parts.size == 2 + file[:specificity] = parts[1] + end + end + end + end +end diff --git a/lib/chef_zero/chef_data/data_normalizer.rb b/lib/chef_zero/chef_data/data_normalizer.rb new file mode 100644 index 0000000..ab45d76 --- /dev/null +++ b/lib/chef_zero/chef_data/data_normalizer.rb @@ -0,0 +1,207 @@ +require 'chef_zero' +require 'chef_zero/rest_base' +require 'chef_zero/chef_data/default_creator' + +module ChefZero + module ChefData + class DataNormalizer + def self.normalize_acls(acls) + ChefData::DefaultCreator::PERMISSIONS.each do |perm| + acls[perm] ||= {} + acls[perm]['actors'] ||= [] + acls[perm]['groups'] ||= [] + end + acls + end + + def self.normalize_client(client, name) + client['name'] ||= name + client['admin'] ||= false + client['admin'] = !!client['admin'] + client['public_key'] ||= PUBLIC_KEY + client['validator'] ||= false + client['validator'] = !!client['validator'] + client['json_class'] ||= "Chef::ApiClient" + client['chef_type'] ||= "client" + client + end + + def self.normalize_container(container, name) + container.delete('id') + container['containername'] = name + container['containerpath'] = name + container + end + + def self.normalize_user(user, name, identity_keys, osc_compat, method=nil) + user[identity_keys.first] ||= name + user['public_key'] ||= PUBLIC_KEY + user['admin'] ||= false + user['admin'] = !!user['admin'] + user['openid'] ||= nil + if !osc_compat + if method == 'GET' + user.delete('admin') + user.delete('password') + user.delete('openid') + end + user['email'] ||= nil + user['first_name'] ||= nil + user['last_name'] ||= nil + end + user + end + + def self.normalize_data_bag_item(data_bag_item, data_bag_name, id, method) + if method == 'DELETE' + # TODO SERIOUSLY, WHO DOES THIS MANY EXCEPTIONS IN THEIR INTERFACE + if !(data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']) + data_bag_item['id'] ||= id + data_bag_item = { 'raw_data' => data_bag_item } + data_bag_item['chef_type'] ||= 'data_bag_item' + data_bag_item['json_class'] ||= 'Chef::DataBagItem' + data_bag_item['data_bag'] ||= data_bag_name + data_bag_item['name'] ||= "data_bag_item_#{data_bag_name}_#{id}" + end + else + # If it's not already wrapped with raw_data, wrap it. + if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data'] + data_bag_item = data_bag_item['raw_data'] + end + # Argh. We don't do this on GET, but we do on PUT and POST???? + if %w(PUT POST).include?(method) + data_bag_item['chef_type'] ||= 'data_bag_item' + data_bag_item['data_bag'] ||= data_bag_name + end + data_bag_item['id'] ||= id + end + data_bag_item + end + + def self.normalize_cookbook(endpoint, org_prefix, cookbook, name, version, base_uri, method) + # 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']]) + end + end + end + end + cookbook['name'] ||= "#{name}-#{version}" + # TODO this feels wrong, but the real chef server doesn't expand this default + # cookbook['version'] ||= version + cookbook['cookbook_name'] ||= name + cookbook['frozen?'] ||= false + cookbook['metadata'] ||= {} + cookbook['metadata']['version'] ||= version + # Sad to not be expanding defaults just because Chef doesn't :( + # cookbook['metadata']['name'] ||= name + # cookbook['metadata']['description'] ||= "A fabulous new cookbook" + cookbook['metadata']['long_description'] ||= "" + # cookbook['metadata']['maintainer'] ||= "YOUR_COMPANY_NAME" + # cookbook['metadata']['maintainer_email'] ||= "YOUR_EMAIL" + # cookbook['metadata']['license'] ||= "none" + cookbook['metadata']['dependencies'] ||= {} + cookbook['metadata']['attributes'] ||= {} + cookbook['metadata']['recipes'] ||= {} + end + cookbook['json_class'] ||= 'Chef::CookbookVersion' + cookbook['chef_type'] ||= 'cookbook_version' + if method == 'MIN' + cookbook['metadata'].delete('attributes') + cookbook['metadata'].delete('long_description') + end + cookbook + end + + def self.normalize_environment(environment, name) + environment['name'] ||= name + environment['description'] ||= '' + environment['cookbook_versions'] ||= {} + environment['json_class'] ||= "Chef::Environment" + environment['chef_type'] ||= "environment" + environment['default_attributes'] ||= {} + environment['override_attributes'] ||= {} + environment + end + + def self.normalize_group(group, name, orgname) + group.delete('id') + if group['actors'].is_a?(Hash) + group['users'] ||= group['actors']['users'] + group['clients'] ||= group['actors']['clients'] + group['groups'] ||= group['actors']['groups'] + group['actors'] = nil + end + group['users'] ||= [] + group['clients'] ||= [] + group['actors'] ||= (group['clients'] + group['users']) + group['groups'] ||= [] + group['orgname'] ||= orgname if orgname + group['name'] ||= name + group['groupname'] ||= name + + group['users'].uniq! + group['clients'].uniq! + group['actors'].uniq! + group['groups'].uniq! + group + end + + def self.normalize_node(node, name) + node['name'] ||= name + node['json_class'] ||= 'Chef::Node' + node['chef_type'] ||= 'node' + node['chef_environment'] ||= '_default' + node['override'] ||= {} + node['normal'] ||= {} + node['default'] ||= {} + node['automatic'] ||= {} + node['run_list'] ||= [] + node['run_list'] = normalize_run_list(node['run_list']) + node + end + + def self.normalize_organization(org, name) + org['name'] ||= name + org['full_name'] ||= name + org['org_type'] ||= 'Business' + org['clientname'] ||= "#{name}-validator" + org['billing_plan'] ||= 'platform-free' + org + end + + def self.normalize_role(role, name) + role['name'] ||= name + role['description'] ||= '' + role['json_class'] ||= 'Chef::Role' + role['chef_type'] ||= 'role' + role['default_attributes'] ||= {} + role['override_attributes'] ||= {} + role['run_list'] ||= [] + role['run_list'] = normalize_run_list(role['run_list']) + role['env_run_lists'] ||= {} + role['env_run_lists'].each_pair do |env, run_list| + role['env_run_lists'][env] = normalize_run_list(run_list) + end + role + end + + def self.normalize_run_list(run_list) + run_list.map{|item| + case item + when /^recipe\[.*\]$/ + item # explicit recipe + when /^role\[.*\]$/ + item # explicit role + else + "recipe[#{item}]" + end + }.uniq + end + end + end +end diff --git a/lib/chef_zero/cookbook_data.rb b/lib/chef_zero/cookbook_data.rb deleted file mode 100644 index 89d5282..0000000 --- a/lib/chef_zero/cookbook_data.rb +++ /dev/null @@ -1,236 +0,0 @@ -require 'digest/md5' -require 'hashie/mash' - -module ChefZero - module CookbookData - def self.to_hash(cookbook, name, version=nil) - frozen = false - if cookbook.has_key?(:frozen) - frozen = cookbook[:frozen] - cookbook = cookbook.dup - cookbook.delete(:frozen) - end - - result = files_from(cookbook) - recipe_names = result[:recipes].map do |recipe| - recipe_name = recipe[:name][0..-2] - recipe_name == 'default' ? name : "#{name}::#{recipe_name}" - end - result[:metadata] = metadata_from(cookbook, name, version, recipe_names) - result[:name] = "#{name}-#{result[:metadata][:version]}" - result[:json_class] = 'Chef::CookbookVersion' - result[:cookbook_name] = name - result[:version] = result[:metadata][:version] - result[:chef_type] = 'cookbook_version' - result[:frozen?] = true if frozen - result - end - - def self.metadata_from(directory, name, version, recipe_names) - metadata = PretendCookbookMetadata.new(PretendCookbook.new(name, recipe_names)) - # If both .rb and .json exist, read .rb - # TODO if recipes has 3 recipes in it, and the Ruby/JSON has only one, should - # the resulting recipe list have 1, or 3-4 recipes in it? - if has_child(directory, 'metadata.rb') - begin - file = filename(directory, 'metadata.rb') || "(#{name}/metadata.rb)" - metadata.instance_eval(read_file(directory, 'metadata.rb'), file) - rescue - ChefZero::Log.error("Error loading cookbook #{name}: #{$!}\n #{$!.backtrace.join("\n ")}") - end - elsif has_child(directory, 'metadata.json') - metadata.from_json(read_file(directory, 'metadata.json')) - end - result = {} - metadata.to_hash.each_pair do |key,value| - result[key.to_sym] = value - end - result[:version] = version if version - result - end - - private - - # Just enough cookbook to make a Metadata object - class PretendCookbook - def initialize(name, fully_qualified_recipe_names) - @name = name - @fully_qualified_recipe_names = fully_qualified_recipe_names - end - attr_reader :name, :fully_qualified_recipe_names - end - - # Handles loading configuration values from a Chef config file - # - # @author Justin Campbell <justin.campbell@riotgames.com> - class PretendCookbookMetadata < Hash - # @param [String] path - def initialize(cookbook) - self.name(cookbook.name) - self.recipes(cookbook.fully_qualified_recipe_names) - %w(attributes grouping dependencies supports recommendations suggestions conflicting providing replacing recipes).each do |hash_arg| - self[hash_arg.to_sym] = Hashie::Mash.new - end - end - - def from_json(json) - self.merge!(JSON.parse(json)) - end - - private - - def depends(cookbook, *version_constraints) - cookbook_arg(:dependencies, cookbook, version_constraints) - end - - def supports(cookbook, *version_constraints) - 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 recipe(recipe, description) - self[:recipes][recipe] = description - end - - def attribute(name, options) - 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 - - def method_missing(key, value = nil) - if value.nil? - self[key.to_sym] - else - store key.to_sym, value - end - end - end - - def self.files_from(directory) - # TODO some support .rb only - 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', false), - :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) - } - set_specificity(result[:templates]) - set_specificity(result[:files]) - result - end - - def self.has_child(directory, name) - if directory.is_a?(Hash) - directory.has_key?(name) - else - directory.child(name).exists? - end - end - - def self.read_file(directory, name) - if directory.is_a?(Hash) - directory[name] - else - directory.child(name).read - end - end - - def self.filename(directory, name) - if directory.respond_to?(:file_path) - File.join(directory.file_path, name) - else - nil - end - end - - def self.get_directory(directory, name) - if directory.is_a?(Hash) - directory[name].is_a?(Hash) ? directory[name] : nil - else - result = directory.child(name) - result.dir? ? result : nil - end - end - - def self.list(directory) - if directory.is_a?(Hash) - directory.keys - else - directory.children.map { |c| c.name } - end - end - - def self.load_child_files(parent, key, recursive) - result = load_files(get_directory(parent, key), recursive) - result.each do |file| - file[:path] = "#{key}/#{file[:path]}" - end - result - end - - def self.load_files(directory, recursive) - result = [] - if directory - list(directory).each do |child_name| - dir = get_directory(directory, child_name) - if dir - if recursive - result += load_child_files(directory, child_name, recursive) - end - else - result += load_file(read_file(directory, child_name), child_name) - end - end - end - result - end - - def self.load_file(value, name) - [{ - :name => name, - :path => name, - :checksum => Digest::MD5.hexdigest(value), - :specificity => 'default' - }] - end - - def self.set_specificity(files) - files.each do |file| - parts = file[:path].split('/') - raise "Only directories are allowed directly under templates or files: #{file[:path]}" if parts.size == 2 - file[:specificity] = parts[1] - end - end - end -end diff --git a/lib/chef_zero/data_normalizer.rb b/lib/chef_zero/data_normalizer.rb deleted file mode 100644 index 39cccc5..0000000 --- a/lib/chef_zero/data_normalizer.rb +++ /dev/null @@ -1,205 +0,0 @@ -require 'chef_zero' -require 'chef_zero/rest_base' -require 'chef_zero/chef_data/default_creator' - -module ChefZero - class DataNormalizer - def self.normalize_acls(acls) - ChefData::DefaultCreator::PERMISSIONS.each do |perm| - acls[perm] ||= {} - acls[perm]['actors'] ||= [] - acls[perm]['groups'] ||= [] - end - acls - end - - def self.normalize_client(client, name) - client['name'] ||= name - client['admin'] ||= false - client['admin'] = !!client['admin'] - client['public_key'] ||= PUBLIC_KEY - client['validator'] ||= false - client['validator'] = !!client['validator'] - client['json_class'] ||= "Chef::ApiClient" - client['chef_type'] ||= "client" - client - end - - def self.normalize_container(container, name) - container.delete('id') - container['containername'] = name - container['containerpath'] = name - container - end - - def self.normalize_user(user, name, identity_keys, osc_compat, method=nil) - user[identity_keys.first] ||= name - user['public_key'] ||= PUBLIC_KEY - user['admin'] ||= false - user['admin'] = !!user['admin'] - user['openid'] ||= nil - if !osc_compat - if method == 'GET' - user.delete('admin') - user.delete('password') - user.delete('openid') - end - user['email'] ||= nil - user['first_name'] ||= nil - user['last_name'] ||= nil - end - user - end - - def self.normalize_data_bag_item(data_bag_item, data_bag_name, id, method) - if method == 'DELETE' - # TODO SERIOUSLY, WHO DOES THIS MANY EXCEPTIONS IN THEIR INTERFACE - if !(data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']) - data_bag_item['id'] ||= id - data_bag_item = { 'raw_data' => data_bag_item } - data_bag_item['chef_type'] ||= 'data_bag_item' - data_bag_item['json_class'] ||= 'Chef::DataBagItem' - data_bag_item['data_bag'] ||= data_bag_name - data_bag_item['name'] ||= "data_bag_item_#{data_bag_name}_#{id}" - end - else - # If it's not already wrapped with raw_data, wrap it. - if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data'] - data_bag_item = data_bag_item['raw_data'] - end - # Argh. We don't do this on GET, but we do on PUT and POST???? - if %w(PUT POST).include?(method) - data_bag_item['chef_type'] ||= 'data_bag_item' - data_bag_item['data_bag'] ||= data_bag_name - end - data_bag_item['id'] ||= id - end - data_bag_item - end - - def self.normalize_cookbook(endpoint, org_prefix, cookbook, name, version, base_uri, method) - # 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']]) - end - end - end - end - cookbook['name'] ||= "#{name}-#{version}" - # TODO this feels wrong, but the real chef server doesn't expand this default - # cookbook['version'] ||= version - cookbook['cookbook_name'] ||= name - cookbook['frozen?'] ||= false - cookbook['metadata'] ||= {} - cookbook['metadata']['version'] ||= version - # Sad to not be expanding defaults just because Chef doesn't :( -# cookbook['metadata']['name'] ||= name -# cookbook['metadata']['description'] ||= "A fabulous new cookbook" - cookbook['metadata']['long_description'] ||= "" -# cookbook['metadata']['maintainer'] ||= "YOUR_COMPANY_NAME" -# cookbook['metadata']['maintainer_email'] ||= "YOUR_EMAIL" -# cookbook['metadata']['license'] ||= "none" - cookbook['metadata']['dependencies'] ||= {} - cookbook['metadata']['attributes'] ||= {} - cookbook['metadata']['recipes'] ||= {} - end - cookbook['json_class'] ||= 'Chef::CookbookVersion' - cookbook['chef_type'] ||= 'cookbook_version' - if method == 'MIN' - cookbook['metadata'].delete('attributes') - cookbook['metadata'].delete('long_description') - end - cookbook - end - - def self.normalize_environment(environment, name) - environment['name'] ||= name - environment['description'] ||= '' - environment['cookbook_versions'] ||= {} - environment['json_class'] ||= "Chef::Environment" - environment['chef_type'] ||= "environment" - environment['default_attributes'] ||= {} - environment['override_attributes'] ||= {} - environment - end - - def self.normalize_group(group, name, orgname) - group.delete('id') - if group['actors'].is_a?(Hash) - group['users'] ||= group['actors']['users'] - group['clients'] ||= group['actors']['clients'] - group['groups'] ||= group['actors']['groups'] - group['actors'] = nil - end - group['users'] ||= [] - group['clients'] ||= [] - group['actors'] ||= (group['clients'] + group['users']) - group['groups'] ||= [] - group['orgname'] ||= orgname if orgname - group['name'] ||= name - group['groupname'] ||= name - - group['users'].uniq! - group['clients'].uniq! - group['actors'].uniq! - group['groups'].uniq! - group - end - - def self.normalize_node(node, name) - node['name'] ||= name - node['json_class'] ||= 'Chef::Node' - node['chef_type'] ||= 'node' - node['chef_environment'] ||= '_default' - node['override'] ||= {} - node['normal'] ||= {} - node['default'] ||= {} - node['automatic'] ||= {} - node['run_list'] ||= [] - node['run_list'] = normalize_run_list(node['run_list']) - node - end - - def self.normalize_organization(org, name) - org['name'] ||= name - org['full_name'] ||= name - org['org_type'] ||= 'Business' - org['clientname'] ||= "#{name}-validator" - org['billing_plan'] ||= 'platform-free' - org - end - - def self.normalize_role(role, name) - role['name'] ||= name - role['description'] ||= '' - role['json_class'] ||= 'Chef::Role' - role['chef_type'] ||= 'role' - role['default_attributes'] ||= {} - role['override_attributes'] ||= {} - role['run_list'] ||= [] - role['run_list'] = normalize_run_list(role['run_list']) - role['env_run_lists'] ||= {} - role['env_run_lists'].each_pair do |env, run_list| - role['env_run_lists'][env] = normalize_run_list(run_list) - end - role - end - - def self.normalize_run_list(run_list) - run_list.map{|item| - case item - when /^recipe\[.*\]$/ - item # explicit recipe - when /^role\[.*\]$/ - item # explicit role - else - "recipe[#{item}]" - end - }.uniq - end - end -end diff --git a/lib/chef_zero/endpoints/acls_endpoint.rb b/lib/chef_zero/endpoints/acls_endpoint.rb index e62fd36..d05abe5 100644 --- a/lib/chef_zero/endpoints/acls_endpoint.rb +++ b/lib/chef_zero/endpoints/acls_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/rest_base' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' require 'chef_zero/chef_data/acl_path' module ChefZero @@ -21,7 +21,7 @@ module ChefZero raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}") end acls = JSON.parse(get_data(request, acl_path), :create_additions => false) - acls = DataNormalizer.normalize_acls(acls) + acls = ChefData::DataNormalizer.normalize_acls(acls) json_response(200, acls) end end diff --git a/lib/chef_zero/endpoints/actor_endpoint.rb b/lib/chef_zero/endpoints/actor_endpoint.rb index ded6530..7b098ff 100644 --- a/lib/chef_zero/endpoints/actor_endpoint.rb +++ b/lib/chef_zero/endpoints/actor_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints @@ -77,9 +77,9 @@ module ChefZero def populate_defaults(request, response_json) response = JSON.parse(response_json, :create_additions => false) if request.rest_path[2] == 'clients' - response = DataNormalizer.normalize_client(response, request.rest_path[3]) + response = ChefData::DataNormalizer.normalize_client(response, request.rest_path[3]) else - response = DataNormalizer.normalize_user(response, request.rest_path[3], identity_keys, server.options[:osc_compat], request.method) + response = ChefData::DataNormalizer.normalize_user(response, request.rest_path[3], identity_keys, server.options[:osc_compat], request.method) end JSON.pretty_generate(response) end diff --git a/lib/chef_zero/endpoints/actors_endpoint.rb b/lib/chef_zero/endpoints/actors_endpoint.rb index 55dac80..90a53d8 100644 --- a/lib/chef_zero/endpoints/actors_endpoint.rb +++ b/lib/chef_zero/endpoints/actors_endpoint.rb @@ -27,7 +27,7 @@ module ChefZero record = get_data(request, request.rest_path + [ name ], :nil) if record record = JSON.parse(record, :create_additions => false) - record = DataNormalizer.normalize_user(record, name, identity_keys, server.options[:osc_compat]) + record = ChefData::DataNormalizer.normalize_user(record, name, identity_keys, server.options[:osc_compat]) results[name] = record end end diff --git a/lib/chef_zero/endpoints/authenticate_user_endpoint.rb b/lib/chef_zero/endpoints/authenticate_user_endpoint.rb index 98dbf04..76751d8 100644 --- a/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +++ b/lib/chef_zero/endpoints/authenticate_user_endpoint.rb @@ -15,7 +15,7 @@ module ChefZero raise RestErrorResponse.new(401, "Bad username or password") end user = JSON.parse(user, :create_additions => false) - user = DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat]) + user = ChefData::DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat]) if user['password'] != password raise RestErrorResponse.new(401, "Bad username or password") end diff --git a/lib/chef_zero/endpoints/container_endpoint.rb b/lib/chef_zero/endpoints/container_endpoint.rb index edb6a7f..e2bb000 100644 --- a/lib/chef_zero/endpoints/container_endpoint.rb +++ b/lib/chef_zero/endpoints/container_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints @@ -14,7 +14,7 @@ module ChefZero def populate_defaults(request, response_json) container = JSON.parse(response_json, :create_additions => false) - container = DataNormalizer.normalize_container(container, request.rest_path[3]) + container = ChefData::DataNormalizer.normalize_container(container, request.rest_path[3]) JSON.pretty_generate(container) end end diff --git a/lib/chef_zero/endpoints/cookbook_version_endpoint.rb b/lib/chef_zero/endpoints/cookbook_version_endpoint.rb index 098c6c6..db33d12 100644 --- a/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +++ b/lib/chef_zero/endpoints/cookbook_version_endpoint.rb @@ -1,7 +1,7 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' require 'chef_zero/rest_error_response' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' require 'chef_zero/data_store/data_not_found_error' module ChefZero @@ -106,7 +106,7 @@ module ChefZero def populate_defaults(request, response_json) # Inject URIs into each cookbook file cookbook = JSON.parse(response_json, :create_additions => false) - cookbook = DataNormalizer.normalize_cookbook(self, request.rest_path[0..1], cookbook, request.rest_path[3], request.rest_path[4], request.base_uri, request.method) + cookbook = ChefData::DataNormalizer.normalize_cookbook(self, request.rest_path[0..1], cookbook, request.rest_path[3], request.rest_path[4], request.base_uri, request.method) JSON.pretty_generate(cookbook) end diff --git a/lib/chef_zero/endpoints/cookbooks_base.rb b/lib/chef_zero/endpoints/cookbooks_base.rb index ccc89ab..76a4914 100644 --- a/lib/chef_zero/endpoints/cookbooks_base.rb +++ b/lib/chef_zero/endpoints/cookbooks_base.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/rest_base' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints diff --git a/lib/chef_zero/endpoints/data_bag_item_endpoint.rb b/lib/chef_zero/endpoints/data_bag_item_endpoint.rb index b92fe92..1ab8793 100644 --- a/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +++ b/lib/chef_zero/endpoints/data_bag_item_endpoint.rb @@ -1,7 +1,7 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' require 'chef_zero/endpoints/data_bag_item_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints @@ -17,7 +17,7 @@ module ChefZero def self.populate_defaults(request, response_json, data_bag, data_bag_item) response = JSON.parse(response_json, :create_additions => false) - response = DataNormalizer.normalize_data_bag_item(response, data_bag, data_bag_item, request.method) + response = ChefData::DataNormalizer.normalize_data_bag_item(response, data_bag, data_bag_item, request.method) JSON.pretty_generate(response) end end diff --git a/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb b/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb index d6e1a80..ae4a85a 100644 --- a/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb @@ -49,7 +49,7 @@ module ChefZero result = {} solved.each_pair do |name, versions| cookbook = JSON.parse(get_data(request, request.rest_path[0..1] + ['cookbooks', name, versions[0]]), :create_additions => false) - result[name] = DataNormalizer.normalize_cookbook(self, request.rest_path[0..1], cookbook, name, versions[0], request.base_uri, 'MIN') + result[name] = ChefData::DataNormalizer.normalize_cookbook(self, request.rest_path[0..1], cookbook, name, versions[0], request.base_uri, 'MIN') end json_response(200, result) end diff --git a/lib/chef_zero/endpoints/environment_endpoint.rb b/lib/chef_zero/endpoints/environment_endpoint.rb index d792b98..74a175b 100644 --- a/lib/chef_zero/endpoints/environment_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints @@ -25,7 +25,7 @@ module ChefZero def populate_defaults(request, response_json) response = JSON.parse(response_json, :create_additions => false) - response = DataNormalizer.normalize_environment(response, request.rest_path[3]) + response = ChefData::DataNormalizer.normalize_environment(response, request.rest_path[3]) JSON.pretty_generate(response) end end diff --git a/lib/chef_zero/endpoints/group_endpoint.rb b/lib/chef_zero/endpoints/group_endpoint.rb index 74d55f6..48f05cd 100644 --- a/lib/chef_zero/endpoints/group_endpoint.rb +++ b/lib/chef_zero/endpoints/group_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints @@ -12,7 +12,7 @@ module ChefZero def populate_defaults(request, response_json) group = JSON.parse(response_json, :create_additions => false) - group = DataNormalizer.normalize_group(group, request.rest_path[3], request.rest_path[1]) + group = ChefData::DataNormalizer.normalize_group(group, request.rest_path[3], request.rest_path[1]) JSON.pretty_generate(group) end end diff --git a/lib/chef_zero/endpoints/node_endpoint.rb b/lib/chef_zero/endpoints/node_endpoint.rb index 5c35e0c..c87e658 100644 --- a/lib/chef_zero/endpoints/node_endpoint.rb +++ b/lib/chef_zero/endpoints/node_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints @@ -8,7 +8,7 @@ module ChefZero class NodeEndpoint < RestObjectEndpoint def populate_defaults(request, response_json) node = JSON.parse(response_json, :create_additions => false) - node = DataNormalizer.normalize_node(node, request.rest_path[3]) + node = ChefData::DataNormalizer.normalize_node(node, request.rest_path[3]) JSON.pretty_generate(node) end end diff --git a/lib/chef_zero/endpoints/organization_endpoint.rb b/lib/chef_zero/endpoints/organization_endpoint.rb index b33b105..4a0bcad 100644 --- a/lib/chef_zero/endpoints/organization_endpoint.rb +++ b/lib/chef_zero/endpoints/organization_endpoint.rb @@ -33,7 +33,7 @@ module ChefZero def populate_defaults(request, response_json) org = JSON.parse(response_json, :create_additions => false) - org = DataNormalizer.normalize_organization(org, request.rest_path[1]) + org = ChefData::DataNormalizer.normalize_organization(org, request.rest_path[1]) JSON.pretty_generate(org) end end diff --git a/lib/chef_zero/endpoints/organization_user_endpoint.rb b/lib/chef_zero/endpoints/organization_user_endpoint.rb index 368a068..c7b4817 100644 --- a/lib/chef_zero/endpoints/organization_user_endpoint.rb +++ b/lib/chef_zero/endpoints/organization_user_endpoint.rb @@ -10,14 +10,14 @@ module ChefZero get_data(request) # 404 if user is not in org user = get_data(request, [ 'users', username ]) user = JSON.parse(user, :create_additions => false) - json_response(200, DataNormalizer.normalize_user(user, username, ['username'], server.options[:osc_compat], request.method)) + json_response(200, ChefData::DataNormalizer.normalize_user(user, username, ['username'], server.options[:osc_compat], request.method)) end def delete(request) user = get_data(request) delete_data(request) user = JSON.parse(user, :create_additions => false) - json_response(200, DataNormalizer.normalize_user(user, request.rest_path[3], ['username'], server.options[:osc_compat])) + json_response(200, ChefData::DataNormalizer.normalize_user(user, request.rest_path[3], ['username'], server.options[:osc_compat])) end end end diff --git a/lib/chef_zero/endpoints/role_endpoint.rb b/lib/chef_zero/endpoints/role_endpoint.rb index 5b7a1b3..6cf91c8 100644 --- a/lib/chef_zero/endpoints/role_endpoint.rb +++ b/lib/chef_zero/endpoints/role_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' module ChefZero module Endpoints @@ -8,7 +8,7 @@ module ChefZero class RoleEndpoint < RestObjectEndpoint def populate_defaults(request, response_json) role = JSON.parse(response_json, :create_additions => false) - role = DataNormalizer.normalize_role(role, request.rest_path[3]) + role = ChefData::DataNormalizer.normalize_role(role, request.rest_path[3]) JSON.pretty_generate(role) end end diff --git a/lib/chef_zero/endpoints/search_endpoint.rb b/lib/chef_zero/endpoints/search_endpoint.rb index 73c44b0..db29f7c 100644 --- a/lib/chef_zero/endpoints/search_endpoint.rb +++ b/lib/chef_zero/endpoints/search_endpoint.rb @@ -1,6 +1,6 @@ require 'json' require 'chef_zero/endpoints/rest_object_endpoint' -require 'chef_zero/data_normalizer' +require 'chef_zero/chef_data/data_normalizer' require 'chef_zero/rest_error_response' require 'chef_zero/solr/solr_parser' require 'chef_zero/solr/solr_doc' @@ -48,15 +48,15 @@ module ChefZero def search_container(request, index) relative_parts, normalize_proc = case index when 'client' - [ ['clients'], Proc.new { |client, name| DataNormalizer.normalize_client(client, name) } ] + [ ['clients'], Proc.new { |client, name| ChefData::DataNormalizer.normalize_client(client, name) } ] when 'node' - [ ['nodes'], Proc.new { |node, name| DataNormalizer.normalize_node(node, name) } ] + [ ['nodes'], Proc.new { |node, name| ChefData::DataNormalizer.normalize_node(node, name) } ] when 'environment' - [ ['environments'], Proc.new { |environment, name| DataNormalizer.normalize_environment(environment, name) } ] + [ ['environments'], Proc.new { |environment, name| ChefData::DataNormalizer.normalize_environment(environment, name) } ] when 'role' - [ ['roles'], Proc.new { |role, name| DataNormalizer.normalize_role(role, name) } ] + [ ['roles'], Proc.new { |role, name| ChefData::DataNormalizer.normalize_role(role, name) } ] else - [ ['data', index], Proc.new { |data_bag_item, id| DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, 'DELETE') } ] + [ ['data', index], Proc.new { |data_bag_item, id| ChefData::DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, 'DELETE') } ] end [ request.rest_path[0..1] + relative_parts, @@ -86,7 +86,7 @@ module ChefZero result elsif !%w(client environment role).include?(index) - DataNormalizer.normalize_data_bag_item(value, index, id, 'GET') + ChefData::DataNormalizer.normalize_data_bag_item(value, index, id, 'GET') else value end diff --git a/lib/chef_zero/endpoints/system_recovery_endpoint.rb b/lib/chef_zero/endpoints/system_recovery_endpoint.rb index 125643b..a3c62fa 100644 --- a/lib/chef_zero/endpoints/system_recovery_endpoint.rb +++ b/lib/chef_zero/endpoints/system_recovery_endpoint.rb @@ -15,7 +15,7 @@ module ChefZero end user = JSON.parse(user, :create_additions => false) - user = DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat]) + user = ChefData::DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat]) if !user['recovery_authentication_enabled'] raise RestErrorResponse.new(403, "Only users with recovery_authentication_enabled=true may use /system_recovery to log in") end diff --git a/lib/chef_zero/endpoints/user_organizations_endpoint.rb b/lib/chef_zero/endpoints/user_organizations_endpoint.rb index aa5034c..98824d6 100644 --- a/lib/chef_zero/endpoints/user_organizations_endpoint.rb +++ b/lib/chef_zero/endpoints/user_organizations_endpoint.rb @@ -13,7 +13,7 @@ module ChefZero result = result.map do |orgname| org = get_data(request, [ 'organizations', orgname, 'org' ]) org = JSON.parse(org, :create_additions => false) - DataNormalizer.normalize_organization(org, orgname) + ChefData::DataNormalizer.normalize_organization(org, orgname) end json_response(200, result) end diff --git a/lib/chef_zero/server.rb b/lib/chef_zero/server.rb index 1f1e29e..a78757f 100644 --- a/lib/chef_zero/server.rb +++ b/lib/chef_zero/server.rb @@ -27,7 +27,7 @@ require 'webrick' require 'webrick/https' require 'chef_zero' -require 'chef_zero/cookbook_data' +require 'chef_zero/chef_data/cookbook_data' require 'chef_zero/rest_router' require 'chef_zero/data_store/memory_store_v2' require 'chef_zero/data_store/v1_to_v2_adapter' @@ -374,9 +374,9 @@ module ChefZero if contents['cookbooks'] contents['cookbooks'].each_pair do |name_version, cookbook| if name_version =~ /(.+)-(\d+\.\d+\.\d+)$/ - cookbook_data = CookbookData.to_hash(cookbook, $1, $2) + cookbook_data = ChefData::CookbookData.to_hash(cookbook, $1, $2) else - cookbook_data = CookbookData.to_hash(cookbook, name_version) + cookbook_data = ChefData::CookbookData.to_hash(cookbook, name_version) end raise "No version specified" if !cookbook_data[:version] data_store.create_dir(['organizations', org_name, 'cookbooks'], cookbook_data[:cookbook_name], :recursive) |