summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <john@johnkeiser.com>2016-01-15 15:07:19 -0800
committerJohn Keiser <john@johnkeiser.com>2016-01-15 15:07:19 -0800
commit12a4a60edefb91a74179ed2e8e58e73018ae9a69 (patch)
treedf9149da15bca278a1b7a511643a5c105c2d3285
parent89d6d7dedcc29bb68341c46f917bc522c24b2539 (diff)
parentf7d83a4d895d5775245e80f4ad857ea92cfc5e02 (diff)
downloadchef-12a4a60edefb91a74179ed2e8e58e73018ae9a69.tar.gz
Merge branch 'jk/policies-local-mode'
-rw-r--r--lib/chef/chef_fs/chef_fs_data_store.rb188
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb38
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb9
3 files changed, 194 insertions, 41 deletions
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb
index 99a668d50d..6bb884c59a 100644
--- a/lib/chef/chef_fs/chef_fs_data_store.rb
+++ b/lib/chef/chef_fs/chef_fs_data_store.rb
@@ -153,9 +153,9 @@ class Chef
if use_memory_store?(path)
@memory_store.create_dir(path, name, *options)
else
- with_dir(path) do |parent|
+ with_parent_dir(path + [name], *options) do |parent, name|
begin
- parent.create_child(chef_fs_filename(path + [name]), nil)
+ parent.create_child(name, nil)
rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
end
@@ -188,10 +188,23 @@ class Chef
elsif path[0] == "cookbooks" && path.length == 2
# Do nothing. The entry gets created when the cookbook is created.
+ # /policy_groups/GROUP/policies/NAME
+ elsif path[0] == "policy_groups" && path[2] == "policies"
+ # Just set or create the proper entry in the hash
+ update_json(to_chef_fs_path(path[0..1]), {}, *options) do |group|
+ if policies.has_key?(path[3])
+ raise ChefZero::DataStore::DataAlreadyExistsError.new(path, group)
+ end
+
+ group["policies"] ||= {}
+ group["policies"][path[3]] = { "revision_id" => Chef::JSONCompat.parse(data) }
+ group
+ end
+
# create [/organizations/ORG]/users/NAME (with content '{}')
# Manipulate the `members.json` file that contains a list of all users
elsif is_org? && path == [ "users" ]
- update_json("members.json", []) do |members|
+ update_json("members.json", [], *options) do |members|
# Format of each entry: { "user": { "username": "jkeiser" } }
if members.any? { |member| member["user"]["username"] == name }
raise ChefZero::DataStore::DataAlreadyExistsError.new(path, entry)
@@ -204,7 +217,7 @@ class Chef
# create [/organizations/ORG]/association_requests/NAME (with content '{}')
# Manipulate the `invitations.json` file that contains a list of all users
elsif is_org? && path == [ "association_requests" ]
- update_json("invitations.json", []) do |invitations|
+ update_json("invitations.json", [], *options) do |invitations|
# Format of each entry: { "id" => "jkeiser-chef", 'username' => 'jkeiser' }
if invitations.any? { |member| member["username"] == name }
raise ChefZero::DataStore::DataAlreadyExistsError.new(path)
@@ -219,9 +232,9 @@ class Chef
raise "set only works with strings"
end
- with_dir(path) do |parent|
+ with_parent_dir(path + [name], *options) do |parent, name|
begin
- parent.create_child(chef_fs_filename(path + [name]), data)
+ parent.create_child(name, data)
rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
end
@@ -243,19 +256,18 @@ class Chef
# /policy_groups/NAME/policies/POLICYNAME: return the revision of the given policy
elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
- with_entry(path[0..1]) do |entry|
- policy_group = Chef::JSONCompat.parse(entry)
- if !policy_group["policies"] || !policy_group["policies"][path[3]] || !policy_group["policies"][path[3]]
- raise ChefZero::DataStore::DataNotFoundError.new(path, entry)
- end
- # The policy group looks like:
- # {
- # "policies": {
- # "x": { "revision_id": "10" }
- # }
- # }
- Chef::JSONCompat.to_json_pretty(policy_group["policies"][path[3]]["revision_id"])
+ # Just set or create the proper entry in the hash
+ policy_group = get_json(to_chef_fs_path(path[0..1]), {})
+ if !policy_group["policies"] || !policy_group["policies"][path[3]]
+ raise ChefZero::DataStore::DataNotFoundError.new(path, entry)
end
+ # The policy group looks like:
+ # {
+ # "policies": {
+ # "x": { "revision_id": "10" }
+ # }
+ # }
+ Chef::JSONCompat.to_json_pretty(policy_group["policies"][path[3]]["revision_id"])
# GET [/organizations/ORG]/users/NAME -> /users/NAME
# Manipulates members.json
@@ -326,13 +338,23 @@ class Chef
# Write out the files!
if path[0] == "cookbooks" && path.length == 3
write_cookbook(path, data, *options)
+
+ # Handle /policy_groups/some_policy_group/policies/some_policy_name
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+ # Just set or create the proper entry in the hash
+ update_json(to_chef_fs_path(path[0..1]), {}, *options) do |group|
+ group["policies"] ||= {}
+ group["policies"][path[3]] = { "revision_id" => Chef::JSONCompat.parse(data) }
+ group
+ end
+
else
- with_dir(path[0..-2]) do |parent|
- child = parent.child(chef_fs_filename(path))
+ with_parent_dir(path, *options) do |parent, name|
+ child = parent.child(name)
if child.exists?
child.write(data)
else
- parent.create_child(chef_fs_filename(path), data)
+ parent.create_child(name, data)
end
end
end
@@ -343,6 +365,16 @@ class Chef
if use_memory_store?(path)
@memory_store.delete(path)
+ # DELETE /policy_groups/GROUP/policies/POLICY
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+ update_json(to_chef_fs_path(path[0..1]), {}) do |group|
+ unless group["policies"] && group["policies"].has_key?(path[3])
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
+ end
+ group["policies"].delete(path[3])
+ group
+ end
+
# DELETE [/organizations/ORG]/users/NAME
# Manipulates members.json
elsif is_org? && path[0] == "users" && path.length == 2
@@ -383,6 +415,24 @@ class Chef
def delete_dir(path, *options)
if use_memory_store?(path)
@memory_store.delete_dir(path, *options)
+
+ # DELETE /policies/POLICY
+ elsif path[0] == "policies" && path.length == 2
+ with_entry(path[0..0]) do |policies|
+ # /policies:
+ # - a-1.0.0.json
+ # - a-1.0.1.json
+ # - b-2.0.0.json
+ found_policy = false
+ policies.children.each do |policy|
+ # We want to delete just the ones that == POLICY
+ next unless policy.name.rpartition('-')[0] == path[1]
+ policy.delete(false)
+ found_policy = true
+ end
+ raise ChefZero::DataStore::DataNotFoundError.new(path) if !found_policy
+ end
+
else
with_entry(path) do |entry|
begin
@@ -398,15 +448,37 @@ class Chef
if use_memory_store?(path)
@memory_store.list(path)
+ # LIST /policies
+ elsif path == [ "policies" ]
+ with_entry([ path[0] ]) do |policies|
+ policies.children.map { |policy| policy.name[0..-6].rpartition('-')[0] }.uniq
+ end
+
+ # LIST /policies/POLICY/revisions
+ elsif path[0] == "policies" && path[2] == "revisions" && path.length == 3
+ with_entry([ path[0] ]) do |policies|
+ # /policies:
+ # - a-1.0.0.json
+ # - a-1.0.1.json
+ # - b-2.0.0.json
+ revisions = []
+ policies.children.each do |policy|
+ name, dash, revision = policy.name[0..-6].rpartition('-')
+ revisions << revision if name == path[1]
+ end
+ raise ChefZero::DataStore::DataNotFoundError.new(path) if revisions.empty?
+ revisions
+ end
+
elsif path[0] == "policy_groups" && path.length == 2
with_entry(path) do |entry|
[ "policies" ]
end
elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 3
- with_entry([ "policy_groups", path[1] ]) do |entry|
- policy_group = Chef::JSONCompat.parse(entry.read)
- (policy_group["policies"] || {}).keys
+ with_entry(path[0..1]) do |entry|
+ policies = Chef::JSONCompat.parse(entry.read)["policies"] || {}
+ policies.keys
end
elsif path[0] == "cookbooks" && path.length == 1
@@ -468,6 +540,12 @@ class Chef
def exists?(path)
if use_memory_store?(path)
@memory_store.exists?(path)
+
+ # /policy_groups/NAME/policies/POLICYNAME
+ elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+ group = get_json(to_chef_fs_path(path[0..1]), {})
+ group["policies"] && group["policies"].has_key?(path[3])
+
else
path_always_exists?(path) || Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
end
@@ -476,14 +554,18 @@ class Chef
def exists_dir?(path)
if use_memory_store?(path)
@memory_store.exists_dir?(path)
+
elsif path[0] == "cookbooks" && path.length == 2
list([ path[0] ]).include?(path[1])
+
+ # /policies/NAME
+ elsif path[0] == "policies" && path.length == 2
+ list([ path[0] ]).include?(path[1])
+
# /policy_groups/NAME/policies
elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 3
exists_dir?(path[0..1])
- # /policy_groups/NAME/policies/POLICYNAME
- elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
- exists_dir?(path[0..1]) && list(path[0..2]).include?(path[3])
+
else
Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
end
@@ -544,17 +626,20 @@ class Chef
end
def _to_chef_fs_path(path)
+ # /data -> /data_bags
+ # /data/BAG -> /data_bags/BAG
+ # /data/BAG/ITEM -> /data_bags/BAG/ITEM.json
if path[0] == "data"
path = path.dup
path[0] = "data_bags"
if path.length >= 3
path[2] = "#{path[2]}.json"
end
- elsif path[0] == "policies"
- path = path.dup
- if path.length >= 3
- path[2] = "#{path[2]}.json"
- end
+
+ # /policies/POLICY/revisions/REVISION -> /policies/POLICY-REVISION.json
+ elsif path[0] == "policies" && path[2] == "revisions" && path.length >= 4
+ path = [ "policies", "#{path[1]}-#{path[3]}.json" ]
+
elsif path[0] == "cookbooks"
if path.length == 2
raise ChefZero::DataStore::DataNotFoundError.new(path)
@@ -618,6 +703,13 @@ class Chef
end
end
+ # /policies/NAME-REVISION.json -> /policies/NAME/revisions/REVISION
+ elsif path[0] == "policies"
+ if path.length >= 2
+ name, dash, revision = path[1][0..-6].rpartition('-')
+ path = [ "policies", name, "revisions", revision ]
+ end
+
elsif path.length == 2 && path[0] != "cookbooks"
path = path.dup
path[1] = path[1][0..-6]
@@ -641,6 +733,17 @@ class Chef
end
end
+ def with_parent_dir(path, *options)
+ path = _to_chef_fs_path(path)
+ begin
+ yield get_dir(path[0..-2], options.include?(:create_dir)), path[-1]
+ rescue Chef::ChefFS::FileSystem::NotFoundError => e
+ err = ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+ err.set_backtrace(e.backtrace)
+ raise err
+ end
+ end
+
def with_dir(path)
# Do not automatically create data bags
create = !(path[0] == "data" && path.size >= 2)
@@ -658,7 +761,7 @@ class Chef
result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join("/"))
if result.exists?
result
- elsif create
+ elsif create || path.size == 1
get_dir(path[0..-2], create).create_child(result.name, nil)
else
raise ChefZero::DataStore::DataNotFoundError.new(path)
@@ -671,16 +774,27 @@ class Chef
metadata[:version] || "0.0.0"
end
- def update_json(path, default_value)
+ def update_json(path, default_value, *options)
entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path)
begin
input = Chef::JSONCompat.parse(entry.read)
- output = yield input.dup
- entry.write(Chef::JSONCompat.to_json_pretty(output)) if output != input
+ output = yield input
+ entry.write(Chef::JSONCompat.to_json_pretty(output)) if output != Chef::JSONCompat.parse(entry.read)
rescue Chef::ChefFS::FileSystem::NotFoundError
# Send the default value to the caller, and create the entry if the caller updates it
output = yield default_value
- entry.parent.create_child(entry.name, Chef::JSONCompat.to_json_pretty(output)) if output != []
+ parent = entry.parent
+ parent = ensure_dir(parent) if options.include?(:create_dir)
+ parent.create_child(entry.name, Chef::JSONCompat.to_json_pretty(output)) if output != []
+ end
+ end
+
+ def ensure_dir(entry)
+ return entry if entry.exists?
+ parent = entry.parent
+ if parent
+ ensure_dir(parent)
+ parent.create_child(entry.name)
end
end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb
new file mode 100644
index 0000000000..a4ad7c11c0
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb
@@ -0,0 +1,38 @@
+#
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/data_handler/policy_data_handler"
+
+class Chef
+ module ChefFS
+ module FileSystem
+ module Repository
+ class ChefRepositoryFileSystemPoliciesDir < ChefRepositoryFileSystemEntry
+ def initialize(name, parent, path = nil)
+ super(name, parent, path, Chef::ChefFS::DataHandler::PolicyDataHandler.new)
+ end
+
+ def can_have_child?(name, is_dir)
+ !is_dir && name.include?("-")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb
index 2add4072ea..8d9f2c21ad 100644
--- a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb
@@ -17,11 +17,12 @@
#
require "chef/chef_fs/file_system/base_fs_dir"
-require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
require "chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir"
require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir"
-require "chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbooks_dir"
require "chef/chef_fs/file_system/repository/chef_repository_file_system_data_bags_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbooks_dir"
require "chef/chef_fs/file_system/multiplexed_dir"
require "chef/chef_fs/data_handler/client_data_handler"
require "chef/chef_fs/data_handler/environment_data_handler"
@@ -170,6 +171,8 @@ class Chef
end
when 'cookbook_artifacts'
dirs = paths.map { |path| ChefRepositoryFileSystemVersionedCookbooksDir.new(name, self, path) }
+ when "policies"
+ dirs = paths.map { |path| ChefRepositoryFileSystemPoliciesDir.new(name, self, path) }
when "data_bags"
dirs = paths.map { |path| ChefRepositoryFileSystemDataBagsDir.new(name, self, path) }
when "acls"
@@ -182,8 +185,6 @@ class Chef
Chef::ChefFS::DataHandler::EnvironmentDataHandler.new
when "nodes"
Chef::ChefFS::DataHandler::NodeDataHandler.new
- when "policies"
- Chef::ChefFS::DataHandler::PolicyDataHandler.new
when "policy_groups"
Chef::ChefFS::DataHandler::PolicyGroupDataHandler.new
when "roles"