diff options
author | John Keiser <jkeiser@opscode.com> | 2014-04-18 13:20:40 -0700 |
---|---|---|
committer | John Keiser <jkeiser@opscode.com> | 2014-04-18 13:20:40 -0700 |
commit | e655c7857e9568ece4555e627fc7d3aa372449ae (patch) | |
tree | 9bff58e253d7e5150d61d4dc6ba7de02cf475335 | |
parent | d66376d5a813fe11a6272ce890fd36bfd32ca0db (diff) | |
download | chef-zero-e655c7857e9568ece4555e627fc7d3aa372449ae.tar.gz |
Add support for "/organizations/chef" prefix
32 files changed, 198 insertions, 159 deletions
@@ -1,6 +1,6 @@ source 'https://rubygems.org' gemspec -gem 'rest-client', :git => 'git://github.com/opscode/rest-client.git' -gem 'chef-pedant', :github => 'opscode/chef-pedant', :ref => 'dbacba4f85e944bd71ea4e9d5324d266750ffc10' +gem 'rest-client', :path => '../rest-client'#:git => 'git://github.com/opscode/rest-client.git' +gem 'chef-pedant', :path => '../chef-pedant'#:github => 'opscode/chef-pedant', :ref => 'dbacba4f85e944bd71ea4e9d5324d266750ffc10' gem 'chef', '>= 11.0' diff --git a/lib/chef_zero/data_normalizer.rb b/lib/chef_zero/data_normalizer.rb index 3e331aa..ffe3c59 100644 --- a/lib/chef_zero/data_normalizer.rb +++ b/lib/chef_zero/data_normalizer.rb @@ -6,8 +6,10 @@ module ChefZero 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 @@ -16,6 +18,8 @@ module ChefZero def self.normalize_user(user, name) user['name'] ||= name user['admin'] ||= false + user['admin'] = !!user['admin'] + user['openid'] ||= nil user['public_key'] ||= PUBLIC_KEY user end @@ -57,14 +61,14 @@ module ChefZero environment end - def self.normalize_cookbook(cookbook, name, version, base_uri, method) + def self.normalize_cookbook(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'] ||= RestBase::build_uri(base_uri, ['file_store', 'checksums', file['checksum']]) + file['url'] ||= RestBase::build_uri(base_uri, org_prefix + ['file_store', 'checksums', file['checksum']]) end end end diff --git a/lib/chef_zero/data_store/memory_store.rb b/lib/chef_zero/data_store/memory_store.rb index 6ed15ee..aa0bb5c 100644 --- a/lib/chef_zero/data_store/memory_store.rb +++ b/lib/chef_zero/data_store/memory_store.rb @@ -29,23 +29,33 @@ module ChefZero def clear @data = {} + create_dir([], 'organizations') + # TODO this should only be automatic when multi_org is false + create_dir([ 'organizations' ], 'chef') + end + + def create_org # Create containers - create_dir([], 'clients') - create_dir([], 'cookbooks') - create_dir([], 'data') - create_dir([], 'environments') - create_dir([], 'file_store') - create_dir(['file_store'], 'checksums') - create_dir([], 'nodes') - create_dir([], 'roles') - create_dir([], 'sandboxes') - create_dir([], 'users') - - # Set defaults - create(['clients'], 'chef-validator', '{ "validator": true }') - create(['clients'], 'chef-webui', '{ "admin": true }') - create(['environments'], '_default', '{ "description": "The default Chef environment" }') - create(['users'], 'admin', '{ "admin": true }') + org = { + 'clients' => { + 'chef-validator' => '{ "validator": true }', + 'chef-webui' => '{ "admin": true }' + }, + 'cookbooks' => {}, + 'data' => {}, + 'environments' => { + '_default' => '{ "description": "The default Chef environment" }' + }, + 'file_store' => { + 'checksums' => {} + }, + 'nodes' => {}, + 'roles' => {}, + 'sandboxes' => {}, + 'users' => { + 'admin' => '{ "admin": "true" }' + } + } end def create_dir(path, name, *options) @@ -56,7 +66,7 @@ module ChefZero raise DataAlreadyExistsError.new(path + [name]) end else - parent[name] = {} + _create_dir(path, parent, name) end end @@ -153,7 +163,7 @@ module ChefZero path.each_with_index do |path_part, index| if !value.has_key?(path_part) if create_dir - value[path_part] = {} + _create_dir(path[0,index], value, path_part) else raise DataNotFoundError.new(path[0,index+1]) end @@ -162,6 +172,14 @@ module ChefZero end value end + + def _create_dir(parent_path, parent, name) + if parent_path == [ 'organizations' ] + parent[name] = create_org + else + parent[name] = {} + end + end end end -end
\ No newline at end of file +end diff --git a/lib/chef_zero/endpoints/actor_endpoint.rb b/lib/chef_zero/endpoints/actor_endpoint.rb index 352a682..f6d93e7 100644 --- a/lib/chef_zero/endpoints/actor_endpoint.rb +++ b/lib/chef_zero/endpoints/actor_endpoint.rb @@ -40,7 +40,7 @@ module ChefZero if result[0] == 200 || result[0] == 201 response = JSON.parse(result[2], :create_additions => false) response['private_key'] = private_key if private_key - response.delete('public_key') if !updating_public_key && request.rest_path[0] == 'users' + response.delete('public_key') if !updating_public_key && request.rest_path[2] == 'users' response.delete('password') json_response(result[0], response) else @@ -50,10 +50,10 @@ module ChefZero def populate_defaults(request, response_json) response = JSON.parse(response_json, :create_additions => false) - if request.rest_path[0] == 'clients' - response = DataNormalizer.normalize_client(response, request.rest_path[1]) + if request.rest_path[2] == 'clients' + response = DataNormalizer.normalize_client(response, request.rest_path[3]) else - response = DataNormalizer.normalize_user(response, request.rest_path[1]) + response = DataNormalizer.normalize_user(response, request.rest_path[3]) end JSON.pretty_generate(response) end diff --git a/lib/chef_zero/endpoints/authenticate_user_endpoint.rb b/lib/chef_zero/endpoints/authenticate_user_endpoint.rb index 37e56a9..f2c26a0 100644 --- a/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +++ b/lib/chef_zero/endpoints/authenticate_user_endpoint.rb @@ -10,7 +10,7 @@ module ChefZero name = request_json['name'] password = request_json['password'] begin - user = data_store.get(['users', name]) + user = data_store.get(request.rest_path[0..1] + ['users', name]) verified = JSON.parse(user, :create_additions => false)['password'] == password rescue DataStore::DataNotFoundError verified = false diff --git a/lib/chef_zero/endpoints/cookbook_endpoint.rb b/lib/chef_zero/endpoints/cookbook_endpoint.rb index a642200..939ef5c 100644 --- a/lib/chef_zero/endpoints/cookbook_endpoint.rb +++ b/lib/chef_zero/endpoints/cookbook_endpoint.rb @@ -5,21 +5,21 @@ module ChefZero # /cookbooks/NAME class CookbookEndpoint < CookbooksBase def get(request) - filter = request.rest_path[1] + filter = request.rest_path[3] case filter when '_latest' result = {} - filter_cookbooks(all_cookbooks_list, {}, 1) do |name, versions| + filter_cookbooks(all_cookbooks_list(request), {}, 1) do |name, versions| if versions.size > 0 - result[name] = build_uri(request.base_uri, ['cookbooks', name, versions[0]]) + result[name] = build_uri(request.base_uri, request.rest_path[0..1] + ['cookbooks', name, versions[0]]) end end json_response(200, result) when '_recipes' result = [] - filter_cookbooks(all_cookbooks_list, {}, 1) do |name, versions| + filter_cookbooks(all_cookbooks_list(request), {}, 1) do |name, versions| if versions.size > 0 - cookbook = JSON.parse(get_data(request, ['cookbooks', name, versions[0]]), :create_additions => false) + cookbook = JSON.parse(get_data(request, request.rest_path[0..1] + ['cookbooks', name, versions[0]]), :create_additions => false) result += recipe_names(name, cookbook) end end diff --git a/lib/chef_zero/endpoints/cookbook_version_endpoint.rb b/lib/chef_zero/endpoints/cookbook_version_endpoint.rb index 3c0fcc6..706382a 100644 --- a/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +++ b/lib/chef_zero/endpoints/cookbook_version_endpoint.rb @@ -9,17 +9,17 @@ module ChefZero # /cookbooks/NAME/VERSION class CookbookVersionEndpoint < RestObjectEndpoint def get(request) - if request.rest_path[2] == "_latest" || request.rest_path[2] == "latest" - request.rest_path[2] = latest_version(list_data(request, request.rest_path[0..1])) + if request.rest_path[4] == "_latest" || request.rest_path[4] == "latest" + request.rest_path[4] = latest_version(list_data(request, request.rest_path[0..3])) end super(request) end def put(request) - name = request.rest_path[1] - version = request.rest_path[2] + name = request.rest_path[3] + version = request.rest_path[4] existing_cookbook = get_data(request, request.rest_path, :nil) - + # Honor frozen if existing_cookbook existing_cookbook_json = JSON.parse(existing_cookbook, :create_additions => false) @@ -37,7 +37,7 @@ module ChefZero end # Set the cookbook - set_data(request, ['cookbooks', name, version], request.body, :create_dir, :create) + set_data(request, request.rest_path[0..1] + ['cookbooks', name, version], request.body, :create_dir, :create) # If the cookbook was updated, check for deleted files and clean them up if existing_cookbook @@ -51,16 +51,16 @@ module ChefZero end def delete(request) - if request.rest_path[2] == "_latest" || request.rest_path[2] == "latest" - request.rest_path[2] = latest_version(list_data(request, request.rest_path[0..1])) + if request.rest_path[4] == "_latest" || request.rest_path[4] == "latest" + request.rest_path[4] = latest_version(list_data(request, request.rest_path[0..3])) end deleted_cookbook = get_data(request) response = super(request) - cookbook_name = request.rest_path[1] - if exists_data_dir?(request, [ 'cookbooks', cookbook_name ]) && list_data(request, ['cookbooks', cookbook_name]).size == 0 - delete_data_dir(request, ['cookbooks', cookbook_name]) + cookbook_name = request.rest_path[3] + if exists_data_dir?(request, request.rest_path[0..1] + [ 'cookbooks', cookbook_name ]) && list_data(request, request.rest_path[0..1] + ['cookbooks', cookbook_name]).size == 0 + delete_data_dir(request, request.rest_path[0..1] + ['cookbooks', cookbook_name]) end # Hoover deleted files, if they exist @@ -85,9 +85,9 @@ module ChefZero private def hoover_unused_checksums(deleted_checksums, request) - data_store.list(['cookbooks']).each do |cookbook_name| - data_store.list(['cookbooks', cookbook_name]).each do |version| - cookbook = data_store.get(['cookbooks', cookbook_name, version], request) + data_store.list(request.rest_path[0..1] + ['cookbooks']).each do |cookbook_name| + data_store.list(request.rest_path[0..1] + ['cookbooks', cookbook_name]).each do |version| + cookbook = data_store.get(request.rest_path[0..1] + ['cookbooks', cookbook_name, version], request) deleted_checksums = deleted_checksums - get_checksums(cookbook) end end @@ -96,7 +96,7 @@ module ChefZero # This deals with an exception on delete, but things can still get deleted # that shouldn't be. begin - data_store.delete(['file_store', 'checksums', checksum]) + data_store.delete(request.rest_path[0..1] + ['file_store', 'checksums', checksum]) rescue ChefZero::DataStore::DataNotFoundError end end @@ -105,7 +105,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(cookbook, request.rest_path[1], request.rest_path[2], request.base_uri, request.method) + cookbook = DataNormalizer.normalize_cookbook(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 2df1dde..ccc89ab 100644 --- a/lib/chef_zero/endpoints/cookbooks_base.rb +++ b/lib/chef_zero/endpoints/cookbooks_base.rb @@ -11,23 +11,23 @@ module ChefZero filter_cookbooks(cookbooks_list, constraints, num_versions) do |name, versions| versions_list = versions.map do |version| { - 'url' => build_uri(request.base_uri, ['cookbooks', name, version]), + 'url' => build_uri(request.base_uri, request.rest_path[0..1] + ['cookbooks', name, version]), 'version' => version } end results[name] = { - 'url' => build_uri(request.base_uri, ['cookbooks', name]), + 'url' => build_uri(request.base_uri, request.rest_path[0..1] + ['cookbooks', name]), 'versions' => versions_list } end results end - def all_cookbooks_list + def all_cookbooks_list(request) result = {} # Race conditions exist here (if someone deletes while listing). I don't care. - data_store.list(['cookbooks']).each do |name| - result[name] = data_store.list(['cookbooks', name]) + data_store.list(request.rest_path[0..1] + ['cookbooks']).each do |name| + result[name] = data_store.list(request.rest_path[0..1] + ['cookbooks', name]) end result end diff --git a/lib/chef_zero/endpoints/cookbooks_endpoint.rb b/lib/chef_zero/endpoints/cookbooks_endpoint.rb index 2c5a8fe..7aaf3e6 100644 --- a/lib/chef_zero/endpoints/cookbooks_endpoint.rb +++ b/lib/chef_zero/endpoints/cookbooks_endpoint.rb @@ -12,7 +12,7 @@ module ChefZero else num_versions = 1 end - json_response(200, format_cookbooks_list(request, all_cookbooks_list, {}, num_versions)) + json_response(200, format_cookbooks_list(request, all_cookbooks_list(request), {}, num_versions)) end end end diff --git a/lib/chef_zero/endpoints/data_bag_endpoint.rb b/lib/chef_zero/endpoints/data_bag_endpoint.rb index 6ae301f..151d25b 100644 --- a/lib/chef_zero/endpoints/data_bag_endpoint.rb +++ b/lib/chef_zero/endpoints/data_bag_endpoint.rb @@ -15,7 +15,7 @@ module ChefZero key = JSON.parse(request.body, :create_additions => false)[identity_key] response = super(request) if response[0] == 201 - already_json_response(201, DataBagItemEndpoint::populate_defaults(request, request.body, request.rest_path[1], key)) + already_json_response(201, DataBagItemEndpoint::populate_defaults(request, request.body, request.rest_path[3], key)) else response end @@ -31,7 +31,7 @@ module ChefZero end def delete(request) - key = request.rest_path[1] + key = request.rest_path[3] delete_data_dir(request, request.rest_path, :recursive) json_response(200, { 'chef_type' => 'data_bag', diff --git a/lib/chef_zero/endpoints/data_bag_item_endpoint.rb b/lib/chef_zero/endpoints/data_bag_item_endpoint.rb index 9c084a3..b92fe92 100644 --- a/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +++ b/lib/chef_zero/endpoints/data_bag_item_endpoint.rb @@ -12,7 +12,7 @@ module ChefZero end def populate_defaults(request, response_json) - DataBagItemEndpoint::populate_defaults(request, response_json, request.rest_path[1], request.rest_path[2]) + DataBagItemEndpoint::populate_defaults(request, response_json, request.rest_path[3], request.rest_path[4]) end def self.populate_defaults(request, response_json, data_bag, data_bag_item) diff --git a/lib/chef_zero/endpoints/data_bags_endpoint.rb b/lib/chef_zero/endpoints/data_bags_endpoint.rb index 7b50ea9..a27b35d 100644 --- a/lib/chef_zero/endpoints/data_bags_endpoint.rb +++ b/lib/chef_zero/endpoints/data_bags_endpoint.rb @@ -10,10 +10,10 @@ module ChefZero name = JSON.parse(contents, :create_additions => false)[identity_key] if name.nil? error(400, "Must specify '#{identity_key}' in JSON") - elsif exists_data_dir?(request, ['data', name]) + elsif exists_data_dir?(request, request.rest_path[0..1] + ['data', name]) error(409, "Object already exists") else - data_store.create_dir(['data'], name, :recursive) + data_store.create_dir(request.rest_path[0..1] + ['data'], name, :recursive) json_response(201, {"uri" => "#{build_uri(request.base_uri, request.rest_path + [name])}"}) end end diff --git a/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb b/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb index f9bb6b1..efba859 100644 --- a/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb @@ -6,10 +6,10 @@ module ChefZero # /environments/NAME/cookbooks/NAME class EnvironmentCookbookEndpoint < CookbooksBase def get(request) - cookbook_name = request.rest_path[3] - environment = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false) + cookbook_name = request.rest_path[5] + environment = JSON.parse(get_data(request, request.rest_path[0..3]), :create_additions => false) constraints = environment['cookbook_versions'] || {} - cookbook_versions = list_data(request, request.rest_path[2..3]) + cookbook_versions = list_data(request, request.rest_path[0..1] + request.rest_path[4..5]) if request.query_params['num_versions'] == 'all' num_versions = nil elsif request.query_params['num_versions'] diff --git a/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb b/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb index 2e56a51..3081ba5 100644 --- a/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb @@ -8,7 +8,7 @@ module ChefZero class EnvironmentCookbookVersionsEndpoint < RestBase def post(request) - cookbook_names = list_data(request, ['cookbooks']) + cookbook_names = list_data(request, request.rest_path[0..1] + ['cookbooks']) # Get the list of cookbooks and versions desired by the runlist desired_versions = {} @@ -16,17 +16,17 @@ module ChefZero run_list.each do |run_list_entry| if run_list_entry =~ /(.+)::.+\@(.+)/ || run_list_entry =~ /(.+)\@(.+)/ raise RestErrorResponse.new(412, "No such cookbook: #{$1}") if !cookbook_names.include?($1) - raise RestErrorResponse.new(412, "No such cookbook version for cookbook #{$1}: #{$2}") if !list_data(request, ['cookbooks', $1]).include?($2) + raise RestErrorResponse.new(412, "No such cookbook version for cookbook #{$1}: #{$2}") if !list_data(request, request.rest_path[0..1] + ['cookbooks', $1]).include?($2) desired_versions[$1] = [ $2 ] else desired_cookbook = run_list_entry.split('::')[0] raise RestErrorResponse.new(412, "No such cookbook: #{desired_cookbook}") if !cookbook_names.include?(desired_cookbook) - desired_versions[desired_cookbook] = list_data(request, ['cookbooks', desired_cookbook]) + desired_versions[desired_cookbook] = list_data(request, request.rest_path[0..1] + ['cookbooks', desired_cookbook]) end end # Filter by environment constraints - environment = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false) + environment = JSON.parse(get_data(request, request.rest_path[0..3]), :create_additions => false) environment_constraints = environment['cookbook_versions'] || {} desired_versions.each_key do |name| @@ -48,8 +48,8 @@ module ChefZero result = {} solved.each_pair do |name, versions| - cookbook = JSON.parse(get_data(request, ['cookbooks', name, versions[0]]), :create_additions => false) - result[name] = DataNormalizer.normalize_cookbook(cookbook, name, versions[0], request.base_uri, 'MIN') + cookbook = JSON.parse(get_data(request, request.rest_path[0..1] + ['cookbooks', name, versions[0]]), :create_additions => false) + result[name] = DataNormalizer.normalize_cookbook(request.rest_path[0..1], cookbook, name, versions[0], request.base_uri, 'MIN') end json_response(200, result) end @@ -74,7 +74,7 @@ module ChefZero new_unsolved = unsolved[1..-1] # Pick this cookbook, and add dependencies - cookbook_obj = JSON.parse(get_data(request, ['cookbooks', solve_for, desired_version]), :create_additions => false) + cookbook_obj = JSON.parse(get_data(request, request.rest_path[0..1] + ['cookbooks', solve_for, desired_version]), :create_additions => false) cookbook_metadata = cookbook_obj['metadata'] || {} cookbook_dependencies = cookbook_metadata['dependencies'] || {} dep_not_found = false @@ -84,12 +84,12 @@ module ChefZero if !new_desired_versions.has_key?(dep_name) new_unsolved = new_unsolved + [dep_name] # If the dep is missing, we will try other versions of the cookbook that might not have the bad dep. - if !exists_data_dir?(request, ['cookbooks', dep_name]) + if !exists_data_dir?(request, request.rest_path[0..1] + ['cookbooks', dep_name]) @last_missing_dep = dep_name.to_s dep_not_found = true break end - new_desired_versions[dep_name] = list_data(request, ['cookbooks', dep_name]) + new_desired_versions[dep_name] = list_data(request, request.rest_path[0..1] + ['cookbooks', dep_name]) new_desired_versions = filter_by_constraint(new_desired_versions, dep_name, environment_constraints[dep_name]) end new_desired_versions = filter_by_constraint(new_desired_versions, dep_name, dep_constraint) diff --git a/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb b/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb index 1222b94..c8f129b 100644 --- a/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb @@ -6,7 +6,7 @@ module ChefZero # /environments/NAME/cookbooks class EnvironmentCookbooksEndpoint < CookbooksBase def get(request) - environment = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false) + environment = JSON.parse(get_data(request, request.rest_path[0..3]), :create_additions => false) constraints = environment['cookbook_versions'] || {} if request.query_params['num_versions'] == 'all' num_versions = nil @@ -15,7 +15,7 @@ module ChefZero else num_versions = 1 end - json_response(200, format_cookbooks_list(request, all_cookbooks_list, constraints, num_versions)) + json_response(200, format_cookbooks_list(request, all_cookbooks_list(request), constraints, num_versions)) end end end diff --git a/lib/chef_zero/endpoints/environment_endpoint.rb b/lib/chef_zero/endpoints/environment_endpoint.rb index a418e78..d792b98 100644 --- a/lib/chef_zero/endpoints/environment_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_endpoint.rb @@ -7,7 +7,7 @@ module ChefZero # /environments/NAME class EnvironmentEndpoint < RestObjectEndpoint def delete(request) - if request.rest_path[1] == "_default" + if request.rest_path[3] == "_default" # 405, really? error(405, "The '_default' environment cannot be modified.") else @@ -16,7 +16,7 @@ module ChefZero end def put(request) - if request.rest_path[1] == "_default" + if request.rest_path[3] == "_default" error(405, "The '_default' environment cannot be modified.") else super(request) @@ -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[1]) + response = DataNormalizer.normalize_environment(response, request.rest_path[3]) JSON.pretty_generate(response) end end diff --git a/lib/chef_zero/endpoints/environment_nodes_endpoint.rb b/lib/chef_zero/endpoints/environment_nodes_endpoint.rb index 91755ef..6e221fd 100644 --- a/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_nodes_endpoint.rb @@ -7,13 +7,13 @@ module ChefZero class EnvironmentNodesEndpoint < RestBase def get(request) # 404 if environment does not exist - get_data(request, request.rest_path[0..1]) + get_data(request, request.rest_path[0..3]) result = {} - list_data(request, ['nodes']).each do |name| - node = JSON.parse(get_data(request, ['nodes', name]), :create_additions => false) - if node['chef_environment'] == request.rest_path[1] - result[name] = build_uri(request.base_uri, ['nodes', name]) + list_data(request, request.rest_path[0..1] + ['nodes']).each do |name| + node = JSON.parse(get_data(request, request.rest_path[0..1] + ['nodes', name]), :create_additions => false) + if node['chef_environment'] == request.rest_path[3] + result[name] = build_uri(request.base_uri, request.rest_path[0..1] + ['nodes', name]) end end json_response(200, result) diff --git a/lib/chef_zero/endpoints/environment_recipes_endpoint.rb b/lib/chef_zero/endpoints/environment_recipes_endpoint.rb index 67d48f3..23c612b 100644 --- a/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_recipes_endpoint.rb @@ -6,12 +6,12 @@ module ChefZero # /environment/NAME/recipes class EnvironmentRecipesEndpoint < CookbooksBase def get(request) - environment = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false) + environment = JSON.parse(get_data(request, request.rest_path[0..3]), :create_additions => false) constraints = environment['cookbook_versions'] || {} result = [] - filter_cookbooks(all_cookbooks_list, constraints, 1) do |name, versions| + filter_cookbooks(all_cookbooks_list(request), constraints, 1) do |name, versions| if versions.size > 0 - cookbook = JSON.parse(get_data(request, ['cookbooks', name, versions[0]]), :create_additions => false) + cookbook = JSON.parse(get_data(request, request.rest_path[0..1] + ['cookbooks', name, versions[0]]), :create_additions => false) result += recipe_names(name, cookbook) end end diff --git a/lib/chef_zero/endpoints/environment_role_endpoint.rb b/lib/chef_zero/endpoints/environment_role_endpoint.rb index 474376b..93c7578 100644 --- a/lib/chef_zero/endpoints/environment_role_endpoint.rb +++ b/lib/chef_zero/endpoints/environment_role_endpoint.rb @@ -8,18 +8,18 @@ module ChefZero class EnvironmentRoleEndpoint < CookbooksBase def get(request) # 404 if environment does not exist - if request.rest_path[0] == 'environments' - environment_path = request.rest_path[0..1] - role_path = request.rest_path[2..3] + if request.rest_path[2] == 'environments' + environment_path = request.rest_path[0..1] + request.rest_path[2..3] + role_path = request.rest_path[0..1] + request.rest_path[4..5] else - environment_path = request.rest_path[2..3] - role_path = request.rest_path[0..1] + environment_path = request.rest_path[0..1] + request.rest_path[4..5] + role_path = request.rest_path[0..1] + request.rest_path[2..3] end # Verify that the environment exists get_data(request, environment_path) role = JSON.parse(get_data(request, role_path), :create_additions => false) - environment_name = environment_path[1] + environment_name = environment_path[3] if environment_name == '_default' run_list = role['run_list'] else diff --git a/lib/chef_zero/endpoints/node_endpoint.rb b/lib/chef_zero/endpoints/node_endpoint.rb index 980008f..5c35e0c 100644 --- a/lib/chef_zero/endpoints/node_endpoint.rb +++ b/lib/chef_zero/endpoints/node_endpoint.rb @@ -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[1]) + node = DataNormalizer.normalize_node(node, request.rest_path[3]) JSON.pretty_generate(node) end end diff --git a/lib/chef_zero/endpoints/principal_endpoint.rb b/lib/chef_zero/endpoints/principal_endpoint.rb index dde9219..2398334 100644 --- a/lib/chef_zero/endpoints/principal_endpoint.rb +++ b/lib/chef_zero/endpoints/principal_endpoint.rb @@ -8,11 +8,11 @@ module ChefZero class PrincipalEndpoint < RestBase def get(request) name = request.rest_path[-1] - json = get_data(request, [ 'users', name ], :nil) + json = get_data(request, request.rest_path[0..1] + [ 'users', name ], :nil) if json type = 'user' else - json = get_data(request, [ 'clients', name ], :nil) + json = get_data(request, request.rest_path[0..1] + [ 'clients', name ], :nil) type = 'client' end if json diff --git a/lib/chef_zero/endpoints/rest_object_endpoint.rb b/lib/chef_zero/endpoints/rest_object_endpoint.rb index a3ce13d..116755d 100644 --- a/lib/chef_zero/endpoints/rest_object_endpoint.rb +++ b/lib/chef_zero/endpoints/rest_object_endpoint.rb @@ -26,7 +26,7 @@ module ChefZero rename = key != request.rest_path[-1] if rename begin - data_store.create(request.rest_path[0..-2], key, request.body) + data_store.create(request.rest_path[0..1] + request.rest_path[2..-2], key, request.body) rescue DataStore::DataAlreadyExistsError return error(409, "Cannot rename '#{request.rest_path[-1]}' to '#{key}': '#{key}' already exists") end diff --git a/lib/chef_zero/endpoints/role_endpoint.rb b/lib/chef_zero/endpoints/role_endpoint.rb index 6a4cfd4..5b7a1b3 100644 --- a/lib/chef_zero/endpoints/role_endpoint.rb +++ b/lib/chef_zero/endpoints/role_endpoint.rb @@ -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[1]) + role = DataNormalizer.normalize_role(role, request.rest_path[3]) JSON.pretty_generate(role) end end diff --git a/lib/chef_zero/endpoints/role_environments_endpoint.rb b/lib/chef_zero/endpoints/role_environments_endpoint.rb index 327602e..caac47c 100644 --- a/lib/chef_zero/endpoints/role_environments_endpoint.rb +++ b/lib/chef_zero/endpoints/role_environments_endpoint.rb @@ -6,7 +6,7 @@ module ChefZero # /roles/NAME/environments class RoleEnvironmentsEndpoint < RestBase def get(request) - role = JSON.parse(get_data(request, request.rest_path[0..1]), :create_additions => false) + role = JSON.parse(get_data(request, request.rest_path[0..3]), :create_additions => false) json_response(200, [ '_default' ] + (role['env_run_lists'].keys || [])) end end diff --git a/lib/chef_zero/endpoints/sandbox_endpoint.rb b/lib/chef_zero/endpoints/sandbox_endpoint.rb index fd7de0a..3a8e139 100644 --- a/lib/chef_zero/endpoints/sandbox_endpoint.rb +++ b/lib/chef_zero/endpoints/sandbox_endpoint.rb @@ -9,14 +9,14 @@ module ChefZero def put(request) existing_sandbox = JSON.parse(get_data(request), :create_additions => false) existing_sandbox['checksums'].each do |checksum| - if !exists_data?(request, ['file_store', 'checksums', checksum]) + if !exists_data?(request, request.rest_path[0..1] + ['file_store', 'checksums', checksum]) raise RestErrorResponse.new(503, "Checksum not uploaded: #{checksum}") end end delete_data(request) json_response(200, { - :guid => request.rest_path[1], - :name => request.rest_path[1], + :guid => request.rest_path[3], + :name => request.rest_path[3], :checksums => existing_sandbox['checksums'], :create_time => existing_sandbox['create_time'], :is_completed => true diff --git a/lib/chef_zero/endpoints/sandboxes_endpoint.rb b/lib/chef_zero/endpoints/sandboxes_endpoint.rb index aa32fb9..09d2175 100644 --- a/lib/chef_zero/endpoints/sandboxes_endpoint.rb +++ b/lib/chef_zero/endpoints/sandboxes_endpoint.rb @@ -16,12 +16,12 @@ module ChefZero needed_checksums = JSON.parse(request.body, :create_additions => false)['checksums'] result_checksums = {} needed_checksums.keys.each do |needed_checksum| - if list_data(request, ['file_store', 'checksums']).include?(needed_checksum) + if list_data(request, request.rest_path[0..1] + ['file_store', 'checksums']).include?(needed_checksum) result_checksums[needed_checksum] = { :needs_upload => false } else result_checksums[needed_checksum] = { :needs_upload => true, - :url => build_uri(request.base_uri, ['file_store', 'checksums', needed_checksum]) + :url => build_uri(request.base_uri, request.rest_path[0..1] + ['file_store', 'checksums', needed_checksum]) } sandbox_checksums << needed_checksum end @@ -48,4 +48,3 @@ module ChefZero end end end - diff --git a/lib/chef_zero/endpoints/search_endpoint.rb b/lib/chef_zero/endpoints/search_endpoint.rb index e6dc3b1..73c44b0 100644 --- a/lib/chef_zero/endpoints/search_endpoint.rb +++ b/lib/chef_zero/endpoints/search_endpoint.rb @@ -46,18 +46,22 @@ module ChefZero private def search_container(request, index) - case index + relative_parts, normalize_proc = case index when 'client' - [ ['clients'], Proc.new { |client, name| DataNormalizer.normalize_client(client, name) }, build_uri(request.base_uri, [ 'clients' ]) ] + [ ['clients'], Proc.new { |client, name| DataNormalizer.normalize_client(client, name) } ] when 'node' - [ ['nodes'], Proc.new { |node, name| DataNormalizer.normalize_node(node, name) }, build_uri(request.base_uri, [ 'nodes' ]) ] + [ ['nodes'], Proc.new { |node, name| DataNormalizer.normalize_node(node, name) } ] when 'environment' - [ ['environments'], Proc.new { |environment, name| DataNormalizer.normalize_environment(environment, name) }, build_uri(request.base_uri, [ 'environments' ]) ] + [ ['environments'], Proc.new { |environment, name| DataNormalizer.normalize_environment(environment, name) } ] when 'role' - [ ['roles'], Proc.new { |role, name| DataNormalizer.normalize_role(role, name) }, build_uri(request.base_uri, [ 'roles' ]) ] + [ ['roles'], Proc.new { |role, name| 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') }, build_uri(request.base_uri, [ 'data', index ]) ] + [ ['data', index], Proc.new { |data_bag_item, id| DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, 'DELETE') } ] end + [ + request.rest_path[0..1] + relative_parts, + normalize_proc + ] end def expand_for_indexing(value, index, id) @@ -90,7 +94,7 @@ module ChefZero def search(request) # Extract parameters - index = request.rest_path[1] + index = request.rest_path[3] query_string = request.query_params['q'] || '*:*' solr_query = ChefZero::Solr::SolrParser.new(query_string).parse sort_string = request.query_params['sort'] @@ -100,14 +104,14 @@ module ChefZero rows = rows.to_i if rows # Get the search container - container, expander, base_uri = search_container(request, index) + container, expander = search_container(request, index) # Search! result = [] list_data(request, container).each do |name| value = get_data(request, container + [name]) expanded = expander.call(JSON.parse(value, :create_additions => false), name) - result << [ name, build_uri(base_uri, [name]), expanded, expand_for_indexing(expanded, index, name) ] + result << [ name, build_uri(request.base_uri, container + [name]), expanded, expand_for_indexing(expanded, index, name) ] end result = result.select do |name, uri, value, search_value| solr_query.matches_doc?(ChefZero::Solr::SolrDoc.new(search_value, name)) diff --git a/lib/chef_zero/endpoints/searches_endpoint.rb b/lib/chef_zero/endpoints/searches_endpoint.rb index dabe164..10deac3 100644 --- a/lib/chef_zero/endpoints/searches_endpoint.rb +++ b/lib/chef_zero/endpoints/searches_endpoint.rb @@ -7,7 +7,7 @@ module ChefZero def get(request) # Get the result result_hash = {} - indices = (%w(client environment node role) + data_store.list(['data'])).sort + indices = (%w(client environment node role) + data_store.list(request.rest_path[0..1] + ['data'])).sort indices.each do |index| result_hash[index] = build_uri(request.base_uri, request.rest_path + [index]) end diff --git a/lib/chef_zero/rest_base.rb b/lib/chef_zero/rest_base.rb index 55dc862..72361ab 100644 --- a/lib/chef_zero/rest_base.rb +++ b/lib/chef_zero/rest_base.rb @@ -28,6 +28,7 @@ module ChefZero begin self.send(method, request) rescue RestErrorResponse => e + ChefZero::Log.debug("#{e.inspect}\n#{e.backtrace.join("\n")}") error(e.response_code, e.error) end end diff --git a/lib/chef_zero/rest_request.rb b/lib/chef_zero/rest_request.rb index 8adefd4..ffea25b 100644 --- a/lib/chef_zero/rest_request.rb +++ b/lib/chef_zero/rest_request.rb @@ -2,11 +2,13 @@ require 'rack/request' module ChefZero class RestRequest - def initialize(env) + def initialize(env, rest_base_prefix = []) @env = env + @rest_base_prefix = rest_base_prefix end attr_reader :env + attr_reader :rest_base_prefix def base_uri @base_uri ||= "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}" @@ -17,7 +19,7 @@ module ChefZero end def rest_path - @rest_path ||= env['PATH_INFO'].split('/').select { |part| part != "" } + @rest_path ||= rest_base_prefix + env['PATH_INFO'].split('/').select { |part| part != "" } end def body=(body) diff --git a/lib/chef_zero/server.rb b/lib/chef_zero/server.rb index 26ccec2..5460d95 100644 --- a/lib/chef_zero/server.rb +++ b/lib/chef_zero/server.rb @@ -65,7 +65,8 @@ module ChefZero :host => '127.0.0.1', :port => 8889, :log_level => :info, - :generate_real_keys => true + :generate_real_keys => true, + :multi_org => true }.freeze def initialize(options = {}) @@ -265,19 +266,20 @@ module ChefZero # } # } # } - def load_data(contents) + def load_data(contents, org_name = 'chef') + create_dir('organizations', org_name) %w(clients environments nodes roles users).each do |data_type| if contents[data_type] dejsonize_children(contents[data_type]).each_pair do |name, data| - data_store.set([data_type, name], data, :create) + data_store.set(['organizations', org_name, data_type, name], data, :create) end end end if contents['data'] contents['data'].each_pair do |key, data_bag| - data_store.create_dir(['data'], key, :recursive) + data_store.create_dir(['organizations', org_name, 'data'], key, :recursive) dejsonize_children(data_bag).each do |item_name, item| - data_store.set(['data', key, item_name], item, :create) + data_store.set(['organizations', org_name, 'data', key, item_name], item, :create) end end end @@ -289,12 +291,12 @@ module ChefZero cookbook_data = CookbookData.to_hash(cookbook, name_version) end raise "No version specified" if !cookbook_data[:version] - data_store.create_dir(['cookbooks'], cookbook_data[:cookbook_name], :recursive) - data_store.set(['cookbooks', cookbook_data[:cookbook_name], cookbook_data[:version]], JSON.pretty_generate(cookbook_data), :create) + data_store.create_dir(['organizations', org_name, 'cookbooks'], cookbook_data[:cookbook_name], :recursive) + data_store.set(['organizations', org_name, 'cookbooks', cookbook_data[:cookbook_name], cookbook_data[:version]], JSON.pretty_generate(cookbook_data), :create) cookbook_data.values.each do |files| next unless files.is_a? Array files.each do |file| - data_store.set(['file_store', 'checksums', file[:checksum]], get_file(cookbook, file[:path]), :create) + data_store.set(['organizations', org_name, 'file_store', 'checksums', file[:checksum]], get_file(cookbook, file[:path]), :create) end end end @@ -319,45 +321,54 @@ module ChefZero private + def open_source_endpoints + [ + [ "/organizations/*/authenticate_user", AuthenticateUserEndpoint.new(self) ], + [ "/organizations/*/clients", ActorsEndpoint.new(self) ], + [ "/organizations/*/clients/*", ActorEndpoint.new(self) ], + [ "/organizations/*/cookbooks", CookbooksEndpoint.new(self) ], + [ "/organizations/*/cookbooks/*", CookbookEndpoint.new(self) ], + [ "/organizations/*/cookbooks/*/*", CookbookVersionEndpoint.new(self) ], + [ "/organizations/*/data", DataBagsEndpoint.new(self) ], + [ "/organizations/*/data/*", DataBagEndpoint.new(self) ], + [ "/organizations/*/data/*/*", DataBagItemEndpoint.new(self) ], + [ "/organizations/*/environments", RestListEndpoint.new(self) ], + [ "/organizations/*/environments/*", EnvironmentEndpoint.new(self) ], + [ "/organizations/*/environments/*/cookbooks", EnvironmentCookbooksEndpoint.new(self) ], + [ "/organizations/*/environments/*/cookbooks/*", EnvironmentCookbookEndpoint.new(self) ], + [ "/organizations/*/environments/*/cookbook_versions", EnvironmentCookbookVersionsEndpoint.new(self) ], + [ "/organizations/*/environments/*/nodes", EnvironmentNodesEndpoint.new(self) ], + [ "/organizations/*/environments/*/recipes", EnvironmentRecipesEndpoint.new(self) ], + [ "/organizations/*/environments/*/roles/*", EnvironmentRoleEndpoint.new(self) ], + [ "/organizations/*/nodes", RestListEndpoint.new(self) ], + [ "/organizations/*/nodes/*", NodeEndpoint.new(self) ], + [ "/organizations/*/principals/*", PrincipalEndpoint.new(self) ], + [ "/organizations/*/roles", RestListEndpoint.new(self) ], + [ "/organizations/*/roles/*", RoleEndpoint.new(self) ], + [ "/organizations/*/roles/*/environments", RoleEnvironmentsEndpoint.new(self) ], + [ "/organizations/*/roles/*/environments/*", EnvironmentRoleEndpoint.new(self) ], + [ "/organizations/*/sandboxes", SandboxesEndpoint.new(self) ], + [ "/organizations/*/sandboxes/*", SandboxEndpoint.new(self) ], + [ "/organizations/*/search", SearchesEndpoint.new(self) ], + [ "/organizations/*/search/*", SearchEndpoint.new(self) ], + [ "/organizations/*/users", ActorsEndpoint.new(self) ], + [ "/organizations/*/users/*", ActorEndpoint.new(self) ], + + [ "/organizations/*/file_store/**", FileStoreFileEndpoint.new(self) ], + ] + end + def app - router = RestRouter.new([ - [ '/authenticate_user', AuthenticateUserEndpoint.new(self) ], - [ '/clients', ActorsEndpoint.new(self) ], - [ '/clients/*', ActorEndpoint.new(self) ], - [ '/cookbooks', CookbooksEndpoint.new(self) ], - [ '/cookbooks/*', CookbookEndpoint.new(self) ], - [ '/cookbooks/*/*', CookbookVersionEndpoint.new(self) ], - [ '/data', DataBagsEndpoint.new(self) ], - [ '/data/*', DataBagEndpoint.new(self) ], - [ '/data/*/*', DataBagItemEndpoint.new(self) ], - [ '/environments', RestListEndpoint.new(self) ], - [ '/environments/*', EnvironmentEndpoint.new(self) ], - [ '/environments/*/cookbooks', EnvironmentCookbooksEndpoint.new(self) ], - [ '/environments/*/cookbooks/*', EnvironmentCookbookEndpoint.new(self) ], - [ '/environments/*/cookbook_versions', EnvironmentCookbookVersionsEndpoint.new(self) ], - [ '/environments/*/nodes', EnvironmentNodesEndpoint.new(self) ], - [ '/environments/*/recipes', EnvironmentRecipesEndpoint.new(self) ], - [ '/environments/*/roles/*', EnvironmentRoleEndpoint.new(self) ], - [ '/nodes', RestListEndpoint.new(self) ], - [ '/nodes/*', NodeEndpoint.new(self) ], - [ '/principals/*', PrincipalEndpoint.new(self) ], - [ '/roles', RestListEndpoint.new(self) ], - [ '/roles/*', RoleEndpoint.new(self) ], - [ '/roles/*/environments', RoleEnvironmentsEndpoint.new(self) ], - [ '/roles/*/environments/*', EnvironmentRoleEndpoint.new(self) ], - [ '/sandboxes', SandboxesEndpoint.new(self) ], - [ '/sandboxes/*', SandboxEndpoint.new(self) ], - [ '/search', SearchesEndpoint.new(self) ], - [ '/search/*', SearchEndpoint.new(self) ], - [ '/users', ActorsEndpoint.new(self) ], - [ '/users/*', ActorEndpoint.new(self) ], - - [ '/file_store/**', FileStoreFileEndpoint.new(self) ], - ]) + router = RestRouter.new(open_source_endpoints) router.not_found = NotFoundEndpoint.new + if options[:multi_org] + rest_base_prefix = [] + else + rest_base_prefix = [ 'organizations', 'chef' ] + end return proc do |env| - request = RestRequest.new(env) + request = RestRequest.new(env, rest_base_prefix) if @on_request_proc @on_request_proc.call(request) end diff --git a/spec/support/pedant.rb b/spec/support/pedant.rb index d21a2f7..39a234d 100644 --- a/spec/support/pedant.rb +++ b/spec/support/pedant.rb @@ -21,7 +21,7 @@ ################################################################################ # You MUST specify the address of the server the API requests will be # sent to. Only specify protocol, hostname, and port. -chef_server 'http://127.0.0.1:8889' +chef_server 'http://127.0.0.1:8889/organizations/chef' # If you are doing development testing, you can specify the address of # the Solr server. The presence of this parameter will enable tests |