summaryrefslogtreecommitdiff
path: root/lib/chef_zero
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2014-08-19 23:53:36 -0700
committerJohn Keiser <jkeiser@opscode.com>2014-08-22 09:20:49 -0700
commit0bccfd74679ae382d04e319972353f9a692bbf30 (patch)
tree35c0b14677bc4ae9dd9974b08721caf711b70659 /lib/chef_zero
parent91768b0e9a0a151635a0a7a96823113b200c67c6 (diff)
downloadchef-zero-0bccfd74679ae382d04e319972353f9a692bbf30.tar.gz
Move all defaults to DefaultCreator, calculate on fly,
remember ownership
Diffstat (limited to 'lib/chef_zero')
-rw-r--r--lib/chef_zero/chef_data/acl_path.rb141
-rw-r--r--lib/chef_zero/chef_data/default_creator.rb428
-rw-r--r--lib/chef_zero/data_normalizer.rb5
-rw-r--r--lib/chef_zero/data_store/default_facade.rb375
-rw-r--r--lib/chef_zero/data_store/memory_store.rb2
-rw-r--r--lib/chef_zero/data_store/memory_store_v2.rb2
-rw-r--r--lib/chef_zero/endpoints/acl_base.rb82
-rw-r--r--lib/chef_zero/endpoints/acl_endpoint.rb13
-rw-r--r--lib/chef_zero/endpoints/acls_endpoint.rb15
-rw-r--r--lib/chef_zero/endpoints/cookbook_version_endpoint.rb3
-rw-r--r--lib/chef_zero/endpoints/data_bag_endpoint.rb1
-rw-r--r--lib/chef_zero/endpoints/data_bags_endpoint.rb2
-rw-r--r--lib/chef_zero/endpoints/rest_object_endpoint.rb3
-rw-r--r--lib/chef_zero/rest_base.rb101
-rw-r--r--lib/chef_zero/rest_error_response.rb2
-rw-r--r--lib/chef_zero/server.rb7
16 files changed, 693 insertions, 489 deletions
diff --git a/lib/chef_zero/chef_data/acl_path.rb b/lib/chef_zero/chef_data/acl_path.rb
new file mode 100644
index 0000000..4592342
--- /dev/null
+++ b/lib/chef_zero/chef_data/acl_path.rb
@@ -0,0 +1,141 @@
+module ChefZero
+ module ChefData
+ # Manages translations between REST and ACL data paths
+ # and parent paths.
+ #
+ # Suggestions
+ # - make /organizations/ORG/_acl and deprecate organization/_acl and organizations/_acl
+ # - add endpoints for /containers/(users|organizations|containers)(/_acl)
+ # - add PUT for */_acl
+ # - add endpoints for /organizations/ORG/data/containers and /organizations/ORG/cookbooks/containers
+ # - sane, fully documented ACL model
+ # - sane inheritance / override model: if actors or groups are explicitly
+ # specified on X, they are not inherited from X's parent
+ # - stop adding pivotal to acls (he already has access to what he needs)
+ module AclPath
+ ORG_DATA_TYPES = %w(clients cookbooks containers data environments groups nodes roles sandboxes)
+ TOP_DATA_TYPES = %w(containers organizations users)
+
+ # ACL data paths for a partition are:
+ # / -> /acls/root
+ # /TYPE -> /acls/containers/TYPE
+ # /TYPE/NAME -> /acls/TYPE/NAME
+ #
+ # The root partition "/" has its own acls, so it looks like this:
+ #
+ # / -> /acls/root
+ # /users -> /acls/containers/users
+ # /organizations -> /acls/containers/organizations
+ # /users/schlansky -> /acls/users/schlansky
+ #
+ # Each organization is its own partition, so it looks like this:
+ #
+ # /organizations/blah -> /organizations/blah/acls/root
+ # /organizations/blah/roles -> /organizations/blah/acls/containers/roles
+ # /organizations/blah/roles/web -> /organizations/blah/acls/roles/web
+ # /organizations/ORG is its own partition. ACLs for anything under it follow
+
+ # This method takes a Chef REST path and returns the chef-zero path
+ # used to look up the ACL. If an object does not have an ACL directly,
+ # it will return nil. Paths like /organizations/ORG/data/bag/item will
+ # return nil, because it is the parent path (data/bag) that has an ACL.
+ def self.get_acl_data_path(path)
+ # Things under organizations have their own acls hierarchy
+ if path[0] == 'organizations' && path.size >= 2
+ under_org = partition_acl_data_path(path[2..-1], ORG_DATA_TYPES)
+ if under_org
+ path[0..1] + under_org
+ end
+ else
+ partition_acl_data_path(path, TOP_DATA_TYPES)
+ end
+ end
+
+ # Reverse transform from acl_data_path to path.
+ # /acls/root -> /
+ # /acls/containers/TYPE -> /TYPE
+ # /acls/TYPE/NAME -> /TYPE/NAME
+ # /organizations/ORG/acls/root -> /
+ # /organizations/ORG/acls/containers/TYPE -> /organizations/ORG/TYPE
+ # /organizations/ORG/acls/TYPE/NAME -> /organizations/ORG/TYPE/NAME
+ #
+ def self.get_object_path(acl_data_path)
+ if acl_data_path[0] == 'acls'
+ if acl_data_path[1] == 'root'
+ []
+ elsif acl_data_path[1] == 'containers'
+ [acl_data_path[2]]
+ else
+ acl_data_path[1..2]
+ end
+ elsif acl_data_path[0] == 'organizations' && acl_data_path[2] == 'acls'
+ if acl_data_path[3] == 'root'
+ acl_data_path[0..1]
+ elsif acl_data_path[3] == 'containers'
+ acl_data_path[0..1] + [ acl_data_path[4] ]
+ else
+ acl_data_path[0..1] + acl_data_path[3..4]
+ end
+ end
+ end
+
+ # Method *assumes* acl_data_path is valid.
+ # /organizations/BLAH's parent is /organizations
+ #
+ # An example traversal up the whole tree:
+ # /organizations/foo/acls/nodes/mario ->
+ # /organizations/foo/acls/containers/nodes ->
+ # /organizations/foo/acls/containers/containers ->
+ # /organizations/foo/acls/root ->
+ # /acls/containers/organizations ->
+ # /acls/containers/containers ->
+ # /acls/root ->
+ # nil
+ def self.parent_acl_data_path(acl_data_path)
+ if acl_data_path[0] == 'organizations'
+ under_org = partition_parent_acl_data_path(acl_data_path[2..-1])
+ if under_org
+ acl_data_path[0..1] + under_org
+ else
+ # ACL data path is /organizations/X/acls/root; therefore parent is "/organizations"
+ [ 'acls', 'containers', 'organizations' ]
+ end
+ else
+ partition_parent_acl_data_path(acl_data_path)
+ end
+ end
+
+ private
+
+ # /acls/root -> nil
+ # /acls/containers/containers -> /acls/root
+ # /acls/TYPE/X -> /acls/containers/TYPE
+ #
+ # Method *assumes* acl_data_path is valid.
+ # Returns nil if the path is /acls/root
+ def self.partition_parent_acl_data_path(acl_data_path)
+ if acl_data_path.size == 3
+ if acl_data_path == %w(acls containers containers)
+ [ 'acls', 'root' ]
+ else
+ [ 'acls', 'containers', acl_data_path[1]]
+ end
+ else
+ nil
+ end
+ end
+
+ def self.partition_acl_data_path(path, data_types)
+ if path.size == 0
+ [ 'acls', 'root']
+ elsif data_types.include?(path[0])
+ if path.size == 0
+ [ 'acls', 'containers', path[0] ]
+ elsif path.size == 2
+ [ 'acls', path[0], path[1] ]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef_zero/chef_data/default_creator.rb b/lib/chef_zero/chef_data/default_creator.rb
new file mode 100644
index 0000000..564a84c
--- /dev/null
+++ b/lib/chef_zero/chef_data/default_creator.rb
@@ -0,0 +1,428 @@
+require 'chef_zero/chef_data/acl_path'
+
+module ChefZero
+ module ChefData
+ #
+ # The DefaultCreator creates default values when you ask for them.
+ # - It relies on created and deleted being called when things get
+ # created and deleted, so that it knows the owners of said objects
+ # and knows to eliminate default values on delete.
+ # - get, list and exists? get data.
+ #
+ class DefaultCreator
+ def initialize(data, single_org, osc_compat, superusers = nil)
+ @data = data
+ @single_org = single_org
+ @osc_compat = osc_compat
+ @superusers = superusers || DEFAULT_SUPERUSERS
+ clear
+ end
+
+ attr_reader :data
+ attr_reader :single_org
+ attr_reader :osc_compat
+ attr_reader :creators
+ attr_reader :deleted
+
+ PERMISSIONS = %w(create read update delete grant)
+ DEFAULT_SUPERUSERS = %w(pivotal)
+
+ def clear
+ @creators = { [] => @superusers }
+ @deleted = {}
+ end
+
+ def deleted(path)
+ # acl deletes mean nothing, they are entirely subservient to their
+ # parent object
+ unless path[0] == 'acls' || (path[0] == 'organizations' && path[2] == 'acls')
+ result = exists?(path)
+ @deleted[path] = true
+ result
+ end
+ false
+ end
+
+ def deleted?(path)
+ 1.upto(path.size) do |index|
+ return true if @deleted[path[0..-index]]
+ end
+ false
+ end
+
+ def created(path, creator)
+ @creators[path] = [ creator ]
+ @deleted.delete(path) if @deleted[path]
+ end
+
+ def superusers
+ @creators[[]]
+ end
+
+ def get(path)
+ return nil if deleted?(path)
+
+ case path[0]
+ when 'acls'
+ # /acls/*
+ object_path = AclPath.get_object_path(path)
+ if data_exists?(object_path)
+ default_acl(path)
+ end
+
+ when 'containers'
+ if path.size == 2 && exists?(path)
+ {}
+ end
+
+ when 'users'
+ if path.size == 2 && data.exists?(path)
+ # User is empty user
+ {}
+ end
+
+ when 'organizations'
+ if path.size >= 2
+ # /organizations/*/**
+ if data.exists_dir?(path[0..1])
+ get_org_default(path)
+ end
+ end
+ end
+ end
+
+ def list(path)
+ return nil if deleted?(path)
+
+ if path.size == 0
+ return %w(containers users organizations acls)
+ end
+
+ case path[0]
+ when 'acls'
+ if path.size == 1
+ [ 'root' ] + data.list(path + [ 'containers' ])
+ else
+ data.list(AclPath.get_object_path(path))
+ end
+
+ when 'containers'
+ [ 'containers', 'users' ]
+
+ when 'users'
+ result = superusers
+ data.list([ 'organizations' ]).each do |org|
+ result += data.list([ 'organizations', org, 'users' ]).uniq
+ end
+ result
+
+ when 'organizations'
+ if path.size == 1
+ single_org ? [ single_org ] : []
+ elsif path.size >= 2 && data.exists_dir?(path[0..1])
+ list_org_default(path)
+ end
+ end
+ end
+
+ def exists?(path)
+ return true if path.size == 0
+ parent_list = list(path[0..-2])
+ parent_list && parent_list.include?(path[-1])
+ end
+
+ protected
+
+ DEFAULT_ORG_SPINE = {
+ 'clients' => {},
+ 'cookbooks' => {},
+ 'data' => {},
+ 'environments' => %w(_default),
+ 'file_store' => {
+ 'checksums' => {}
+ },
+ 'nodes' => {},
+ 'roles' => {},
+ 'sandboxes' => {},
+ 'users' => {},
+
+ 'org' => {},
+ 'containers' => %w(clients containers cookbooks data environments groups nodes roles sandboxes),
+ 'groups' => %w(admins billing-admins clients users),
+ 'association_requests' => {}
+ }
+
+ def list_org_default(path)
+ if path.size >= 3 && path[2] == 'acls'
+ if path.size == 3
+ return [ 'root' ] + data.list(path[0..1] + [ 'containers' ])
+ else
+ return data.list(AclPath.get_object_path(path))
+ end
+ end
+
+ value = DEFAULT_ORG_SPINE
+ 2.upto(path.size-1) do |index|
+ value = nil if @deleted[path[0..index]]
+ break if !value
+ value = value[path[index]]
+ end
+
+ result = if value.is_a?(Hash)
+ value.keys
+ elsif value
+ value
+ end
+
+ if path.size == 3
+ if path[2] == 'clients'
+ result << "#{path[1]}-validator"
+ if osc_compat
+ result << "#{path[1]}-webui"
+ end
+ elsif path[2] == 'users'
+ if osc_compat
+ result << 'admin'
+ else
+ result += @creators[path[0..1]] if @creators[path[0..1]]
+ end
+ end
+ end
+
+ result
+ end
+
+ def get_org_default(path)
+ if path[2] == 'acls'
+ get_org_acl_default(path)
+
+ elsif path.size >= 4
+ if !osc_compat && path[2] == 'users'
+ if @creators[path[0..1]] && @creators[path[0..1]].include?(path[3])
+ return {}
+ end
+ end
+
+ if path[2] == 'containers' && path.size == 4
+ if exists?(path)
+ return {}
+ else
+ return nil
+ end
+ end
+
+
+ # /organizations/(*)/clients/\1-validator
+ # /organizations/*/environments/_default
+ # /organizations/*/groups/{admins,billing-admins,clients,users}
+ case path[2..-1].join('/')
+ when "clients/#{path[1]}-validator"
+ { 'validator' => 'true' }
+
+ when "clients/#{path[1]}-webui", "users/admin"
+ if osc_compat
+ { 'admin' => 'true' }
+ end
+
+ when "environments/_default"
+ { "description" => "The default Chef environment" }
+
+ when "groups/admins"
+ admins = data.list(path[0..1] + [ 'users' ]).select do |name|
+ user = JSON.parse(data.get(path[0..1] + [ 'users', name ]), :create_additions => false)
+ user['admin']
+ end
+ admins += data.list(path[0..1] + [ 'clients' ]).select do |name|
+ client = JSON.parse(data.get(path[0..1] + [ 'clients', name ]), :create_additions => false)
+ client['admin']
+ end
+ admins += @creators[path[0..1]] if @creators[path[0..1]]
+ { 'actors' => admins.uniq }
+
+ when "groups/billing-admins"
+ {}
+
+ when "groups/clients"
+ { 'clients' => data.list(path[0..1] + [ 'clients' ]) }
+
+ when "groups/users"
+ users = data.list(path[0..1] + [ 'users' ])
+ users += @creators[path[0..1]] if @creators[path[0..1]]
+ { 'users' => users.uniq }
+
+ when "org"
+ {}
+
+ end
+ end
+ end
+
+ def get_org_acl_default(path)
+ object_path = AclPath.get_object_path(path)
+ return nil if !data_exists?(object_path)
+ basic_acl =
+ case path[3..-1].join('/')
+ when 'root', 'containers/containers', 'containers/groups'
+ {
+ 'create' => { 'groups' => %w(admins) },
+ 'read' => { 'groups' => %w(admins users) },
+ 'update' => { 'groups' => %w(admins) },
+ 'delete' => { 'groups' => %w(admins) },
+ 'grant' => { 'groups' => %w(admins) },
+ }
+ when 'containers/cookbooks', 'containers/environments', 'containers/roles'
+ {
+ 'create' => { 'groups' => %w(admins users) },
+ 'read' => { 'groups' => %w(admins users clients) },
+ 'update' => { 'groups' => %w(admins users) },
+ 'delete' => { 'groups' => %w(admins users) },
+ 'grant' => { 'groups' => %w(admins) },
+ }
+ when 'containers/cookbooks', 'containers/data'
+ {
+ 'create' => { 'groups' => %w(admins users clients) },
+ 'read' => { 'groups' => %w(admins users clients) },
+ 'update' => { 'groups' => %w(admins users clients) },
+ 'delete' => { 'groups' => %w(admins users clients) },
+ 'grant' => { 'groups' => %w(admins) },
+ }
+ when 'containers/nodes'
+ {
+ 'create' => { 'groups' => %w(admins users clients) },
+ 'read' => { 'groups' => %w(admins users clients) },
+ 'update' => { 'groups' => %w(admins users) },
+ 'delete' => { 'groups' => %w(admins users) },
+ 'grant' => { 'groups' => %w(admins) },
+ }
+ when 'containers/clients'
+ {
+ 'create' => { 'groups' => %w(admins) },
+ 'read' => { 'groups' => %w(admins users) },
+ 'update' => { 'groups' => %w(admins) },
+ 'delete' => { 'groups' => %w(admins users) },
+ 'grant' => { 'groups' => %w(admins) },
+ }
+ when 'containers/sandboxes'
+ {
+ 'create' => { 'groups' => %w(admins users) },
+ 'read' => { 'groups' => %w(admins) },
+ 'update' => { 'groups' => %w(admins) },
+ 'delete' => { 'groups' => %w(admins) },
+ 'grant' => { 'groups' => %w(admins) },
+ }
+ when 'groups/admins', 'groups/clients', 'groups/users'
+ {
+ 'create' => { 'groups' => %w(admins) },
+ 'read' => { 'groups' => %w(admins) },
+ 'update' => { 'groups' => %w(admins) },
+ 'delete' => { 'groups' => %w(admins) },
+ 'grant' => { 'groups' => %w(admins) },
+ }
+ when 'groups/billing-admins'
+ {
+ 'create' => { 'groups' => %w() },
+ 'read' => { 'groups' => %w(billing-admins) },
+ 'update' => { 'groups' => %w(billing-admins) },
+ 'delete' => { 'groups' => %w() },
+ 'grant' => { 'groups' => %w() },
+ }
+ else
+ {}
+ end
+
+ default_acl(path, basic_acl)
+ end
+
+ def get_owners(acl_path)
+ owners = []
+
+ path = AclPath.get_object_path(acl_path)
+ if path
+
+ # Add the actual owner
+ if @creators[path]
+ owners += @creators[path]
+ end
+
+ # The objects that were created with the org itself have the peculiar
+ # property of missing superusers from their acl.
+ # if !exists?(path)
+ owners += superusers
+ # end
+
+ # Clients need to be in their own acl list, except the validator created with the org
+ # (which we test for with exists?, which only looks at the defaults)
+ if path.size == 4 && path[0] == 'organizations' && path[2] == 'clients' && !exists?(path)
+ owners |= [ path[3] ]
+ end
+
+ end
+
+ owners.uniq
+ end
+
+ def default_acl(acl_path, acl={})
+ owners = nil
+ container_acl = nil
+ PERMISSIONS.each do |perm|
+ acl[perm] ||= {}
+ acl[perm]['actors'] ||= begin
+ owners ||= get_owners(acl_path)
+ container_acl ||= get_container_acl(acl_path) || {}
+ if container_acl[perm] && container_acl[perm]['actors']
+ owners | container_acl[perm]['actors']
+ else
+ owners
+ end
+ end
+ acl[perm]['groups'] ||= begin
+ # When we create containers, we don't merge groups (not sure why).
+ if acl_path[0] == 'organizations' && acl_path[3] == 'containers'
+ []
+ else
+ container_acl ||= get_container_acl(request, acl_path) || {}
+ (container_acl[perm] ? container_acl[perm]['groups'] : []) || []
+ end
+ end
+ end
+ acl
+ end
+
+ def get_container_acl(acl_path)
+ parent_path = AclPath.parent_acl_data_path(acl_path)
+ if parent_path
+ JSON.parse(data.get(parent_path), :create_additions => false)
+ else
+ nil
+ end
+ end
+
+ def data_exists?(path)
+ if is_dir?(path)
+ data.exists_dir?(path)
+ else
+ data.exists?(path)
+ end
+ end
+
+ def is_dir?(path)
+ case path.size
+ when 0, 1
+ return true
+ when 2
+ return path[0] == 'organizations' || (path[0] == 'acls' && path[1] != 'root')
+ when 3
+ # If it has a container, it is a directory.
+ return path[0] == 'organizations' &&
+ (path[2] == 'acls' || data.exists?(path[0..1] + [ 'containers', path[2] ]))
+ when 4
+ return path[0] == 'organizations' && (
+ (path[2] == 'acls' && path[1] != 'root') ||
+ %w(cookbooks data).include?(path[2]))
+ else
+ return false
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef_zero/data_normalizer.rb b/lib/chef_zero/data_normalizer.rb
index 93ba370..89edfeb 100644
--- a/lib/chef_zero/data_normalizer.rb
+++ b/lib/chef_zero/data_normalizer.rb
@@ -1,13 +1,14 @@
require 'chef_zero'
require 'chef_zero/rest_base'
+require 'chef_zero/chef_data/default_creator'
module ChefZero
class DataNormalizer
def self.normalize_acls(acls)
- %w(create read update delete grant).each do |perm|
+ ChefData::DefaultCreator::PERMISSIONS.each do |perm|
acls[perm] ||= {}
acls[perm]['actors'] ||= []
- acls[perm]['groups'] ||= [ ]
+ acls[perm]['groups'] ||= []
end
acls
end
diff --git a/lib/chef_zero/data_store/default_facade.rb b/lib/chef_zero/data_store/default_facade.rb
index 74d1ba4..abc3f47 100644
--- a/lib/chef_zero/data_store/default_facade.rb
+++ b/lib/chef_zero/data_store/default_facade.rb
@@ -1,151 +1,77 @@
require 'chef_zero/data_store/interface_v2'
+require 'chef_zero/chef_data/default_creator'
module ChefZero
module DataStore
+ #
+ # The DefaultFacade exists to layer defaults on top of an existing data
+ # store. When you create an org, you just create the directory itself:
+ # the rest of the org (such as environments/_default) will not actually
+ # exist anywhere, but when you get(/organizations/org/environments/_default),
+ # the DefaultFacade will create one for you on the fly.
+ #
+ # acls in particular are instantiated on the fly using this method.
+ #
class DefaultFacade < ChefZero::DataStore::InterfaceV2
- def initialize(real_store, osc_compat, superusers = nil)
+ def initialize(real_store, single_org, osc_compat, superusers = nil)
@real_store = real_store
- @osc_compat = osc_compat
- @superusers = superusers || (osc_compat ? [] : DefaultFacade::DEFAULT_SUPERUSERS)
+ @default_creator = ChefData::DefaultCreator.new(self, single_org, osc_compat, superusers)
clear
end
attr_reader :real_store
- attr_reader :osc_compat
- attr_reader :superusers
-
- DEFAULT_SUPERUSERS = [ 'pivotal' ]
-
- def default(path, name=nil)
- value = @defaults
- for part in path
- break if !value
- value = value[part]
- end
- value = value[name] if value && name
- if value.is_a?(Proc)
- return value.call(self, path)
- else
- if value.nil?
- # ACLs are a special case: defaults for them exist as long as the
- # underlying object does
- if (path[0] == 'acls' || (path[0] == 'organizations' && path[2] == 'acls')) &&
- target_object_exists?(path)
- return '{}'
- end
- end
- return value
- end
- end
-
- def target_object_exists?(acl_path)
- if acl_path[0] == 'organizations'
- org_path = acl_path[0..1]
- object_part = acl_path[3..-1]
- if object_part == [ 'organization' ]
- exists_dir?(org_path)
- else
- path = org_path + object_part
- if object_part.size == 2 && %w(cookbooks data).include?(object_part[0])
- exists_dir?(path)
- else
- exists?(path)
- end
- end
- elsif acl_path[0] == 'acls'
- exists?(acl_path[1..-1])
- end
- end
-
- def delete_default(path)
- value = @defaults
- for part in path[0..-2]
- break if !value
- value = value[part]
- end
- if value
- !!value.delete(path[-1])
- else
- false
- end
- end
+ attr_reader :default_creator
def clear
real_store.clear if real_store.respond_to?(:clear)
- @defaults = {
- 'organizations' => {},
- 'acls' => {}
- }
- unless osc_compat
- @defaults['users'] = {}
- @defaults['superusers'] = {}
-
- superusers.each do |superuser|
- @defaults['users'][superuser] = '{}'
- @defaults['superusers'][superuser] = '{}'
- end
- end
+ default_creator.clear
end
def create_dir(path, name, *options)
- if default(path, name) && !options.include?(:recursive)
+ if default_creator.exists?(path + [ name ]) && !options.include?(:recursive)
raise DataAlreadyExistsError.new(path + [name])
end
+
begin
real_store.create_dir(path, name, *options)
rescue DataNotFoundError
- if default(path)
+ if default_creator.exists?(path)
real_store.create_dir(path, name, :recursive, *options)
else
raise
end
end
- # If the org hasn't been created, create its defaults
- if path.size > 0 && path[0] == 'organizations'
- options_hash = options.last
- requestor = options_hash.is_a?(Hash) ? options_hash[:requestor] : nil
- if path.size == 1
- orgname = name
- else
- orgname = path[1]
- end
- @defaults['organizations'][orgname] ||= DefaultFacade.org_defaults(orgname, requestor, superusers, osc_compat)
- end
+ options_hash = options.last.is_a?(Hash) ? options.last : {}
+ default_creator.created(path + [ name ], options_hash[:requestor])
end
def create(path, name, data, *options)
- if default(path, name) && !options.include?(:create_dir)
+ if default_creator.exists?(path + [ name ]) && !options.include?(:create_dir)
raise DataAlreadyExistsError.new(path + [name])
end
+
begin
real_store.create(path, name, data, *options)
rescue DataNotFoundError
- if default(path)
+ if default_creator.exists?(path)
real_store.create(path, name, data, :create_dir, *options)
else
raise
end
end
- # If the org hasn't been created, create its defaults
- if path.size > 0 && path[0] == 'organizations'
- options_hash = options.last
- requestor = options_hash.is_a?(Hash) ? options_hash[:requestor] : nil
- if path.size == 1
- @defaults['organizations'][name] ||= DefaultFacade.org_defaults(name, options[:requestor], superusers, osc_compat)
- else
- @defaults['organizations'][path[1]] ||= DefaultFacade.org_defaults(path[1], options[:requestor], suepruserse, osc_compat)
- end
- end
+
+ options_hash = options.last || {}
+ default_creator.created(path + [ name ], options_hash[:requestor])
end
def get(path, request=nil)
begin
real_store.get(path, request)
rescue DataNotFoundError
- result = default(path)
+ result = default_creator.get(path)
if result
- result
+ JSON.pretty_generate(result)
else
raise
end
@@ -156,7 +82,7 @@ module ChefZero
begin
real_store.set(path, data, *options)
rescue DataNotFoundError
- if default(path)
+ if default_creator.exists?(path)
real_store.set(path, data, :create, :create_dir, *options)
else
raise
@@ -165,20 +91,18 @@ module ChefZero
end
def delete(path)
- deleted = delete_default(path)
+ deleted = default_creator.deleted(path)
begin
real_store.delete(path)
rescue DataNotFoundError
- if deleted
- return
- else
+ if !deleted
raise
end
end
end
def delete_dir(path, *options)
- deleted = delete_default(path)
+ deleted = default_creator.deleted(path)
begin
real_store.delete_dir(path, *options)
rescue DataNotFoundError
@@ -189,8 +113,7 @@ module ChefZero
end
def list(path)
- default_results = default(path)
- default_results = default_results.keys if default_results
+ default_results = default_creator.list(path)
begin
real_results = real_store.list(path)
if default_results
@@ -208,241 +131,11 @@ module ChefZero
end
def exists?(path)
- real_store.exists?(path) || default(path)
+ real_store.exists?(path) || default_creator.exists?(path)
end
def exists_dir?(path)
- real_store.exists_dir?(path) || default(path)
- end
-
- def self.org_defaults(name, creator, superusers, osc_compat)
- result = {
- 'clients' => {
- "#{name}-validator" => '{ "validator": true }'
- },
- 'cookbooks' => {},
- 'data' => {},
- 'environments' => {
- '_default' => '{ "description": "The default Chef environment" }'
- },
- 'file_store' => {
- 'checksums' => {}
- },
- 'nodes' => {},
- 'roles' => {},
- 'sandboxes' => {},
- 'users' => {},
-
- 'org' => '{}',
- 'containers' => {
- 'clients' => '{}',
- 'containers' => '{}',
- 'cookbooks' => '{}',
- 'data' => '{}',
- 'environments' => '{}',
- 'groups' => '{}',
- 'nodes' => '{}',
- 'roles' => '{}',
- 'sandboxes' => '{}'
- },
- 'groups' => {
- 'admins' => admins_group(creator),
- 'billing-admins' => '{}',
- 'clients' => clients_group,
- 'users' => users_group(creator),
- },
- 'acls' => {
- 'clients' => {},
- 'containers' => {
- 'cookbooks' => fill_acls(creator, {
- :create => %w(admins users),
- :read => %w(admins users clients),
- :update => %w(admins users),
- :delete => %w(admins users),
- :grant => %w(admins)
- }),
- 'environments' => fill_acls(creator, {
- :create => %w(admins users),
- :read => %w(admins users clients),
- :update => %w(admins users),
- :delete => %w(admins users),
- :grant => %w(admins)
- }),
- 'roles' => fill_acls(creator, {
- :create => %w(admins users),
- :read => %w(admins users clients),
- :update => %w(admins users),
- :delete => %w(admins users),
- :grant => %w(admins)
- }),
- 'data' => fill_acls(creator, {
- :create => %w(admins users clients),
- :read => %w(admins users clients),
- :update => %w(admins users clients),
- :delete => %w(admins users clients),
- :grant => %w(admins)
- }),
- 'nodes' => fill_acls(creator, {
- :create => %w(admins users clients),
- :read => %w(admins users clients),
- :update => %w(admins users),
- :delete => %w(admins users),
- :grant => %w(admins)
- }),
- 'clients' => fill_acls(creator, {
- :create => %w(admins),
- :read => %w(admins users),
- :update => %w(admins),
- :delete => %w(admins users),
- :grant => %w(admins)
- }),
- 'groups' => fill_acls(creator, {
- :create => %w(admins),
- :read => %w(admins users),
- :update => %w(admins),
- :delete => %w(admins),
- :grant => %w(admins)
- }),
- 'containers' => fill_acls(creator, {
- :create => %w(admins),
- :read => %w(admins users),
- :update => %w(admins),
- :delete => %w(admins),
- :grant => %w(admins)
- }),
- 'sandboxes' => fill_acls(creator, {
- :create => %w(admins users),
- :read => %w(admins),
- :update => %w(admins),
- :delete => %w(admins),
- :grant => %w(admins)
- })
- },
- 'cookbooks' => {},
- 'data' => {},
- 'environments' => {},
- 'groups' => {
- # It's a little weird that the default acls for groups
- # allows users to read, but these groups don't.
- 'admins' => '{ "read": { "groups": [ "admins" ] } }',
- 'clients' => '{ "read": { "groups": [ "admins" ] } }',
- 'users' => '{ "read": { "groups": [ "admins" ] } }',
- 'billing-admins' => '{
- "create": { "groups": [ ] },
- "read": { "groups": [ "billing-admins" ] },
- "update": { "groups": [ "billing-admins" ] },
- "delete": { "groups": [ ] },
- "grant": { "groups": [ ] }
- }',
- },
- 'nodes' => {},
- 'roles' => {},
- 'organization' => org_acls,
- 'organizations' => fill_acls(creator, {
- :create => %w(admins),
- :read => %w(admins users),
- :update => %w(admins),
- :delete => %w(admins),
- :grant => %w(admins)
- }),
- 'sandboxes' => {}
- },
- 'association_requests' => {}
- }
-
- if osc_compat
- result['users']['admin'] = '{ "admin": "true" }'
- result['clients']["#{name}-webui"] = '{ "admin": true }'
- else
- result['users'][creator] = '{}'
- end
-
- result
- end
-
- private
-
- def self.org_acls
- proc do |data, path|
- superusers = data.list([ 'superusers' ])
- acls = {
- 'create' => {
- 'actors' => superusers,
- 'groups' => %w(admins)
- },
- 'read' => {
- 'actors' => superusers,
- 'groups' => %w(admins users)
- },
- 'update' => {
- 'actors' => superusers,
- 'groups' => %w(admins)
- },
- 'delete' => {
- 'actors' => superusers,
- 'groups' => %w(admins)
- },
- 'grant' => {
- 'actors' => superusers,
- 'groups' => %w(admins)
- }
- }
- JSON.pretty_generate(acls)
- end
- end
-
- def self.fill_acls(creator, group_acls)
- acls = {
- 'create' => {
- 'actors' => [ creator ],
- 'groups' => group_acls[:create]
- },
- 'read' => {
- 'actors' => [ creator ],
- 'groups' => group_acls[:read]
- },
- 'update' => {
- 'actors' => [ creator ],
- 'groups' => group_acls[:update]
- },
- 'delete' => {
- 'actors' => [ creator ],
- 'groups' => group_acls[:delete]
- },
- 'grant' => {
- 'actors' => [ creator ],
- 'groups' => group_acls[:grant]
- }
- }
- return JSON.pretty_generate(acls)
- end
-
- def self.admins_group(creator)
- proc do |data, path|
- admins = data.list(path[0..1] + [ 'users' ]).select do |name|
- user = JSON.parse(data.get(path[0..1] + [ 'users', name ]), :create_additions => false)
- user['admin']
- end
- admins += data.list(path[0..1] + [ 'clients' ]).select do |name|
- client = JSON.parse(data.get(path[0..1] + [ 'clients', name ]), :create_additions => false)
- client['admin']
- end
- JSON.pretty_generate({ 'actors' => ([ creator ] + admins).uniq })
- end
- end
-
- def self.clients_group
- proc do |data, path|
- clients = data.list(path[0..1] + [ 'clients' ])
- JSON.pretty_generate({ 'clients' => clients })
- end
- end
-
- def self.users_group(creator)
- proc do |data, path|
- users = data.list(path[0..1] + [ 'users' ])
- JSON.pretty_generate({ 'users' => ([ creator ] + users).uniq })
- end
+ real_store.exists_dir?(path) || default_creator.exists?(path)
end
end
end
diff --git a/lib/chef_zero/data_store/memory_store.rb b/lib/chef_zero/data_store/memory_store.rb
index 2c8251d..bfbe9d6 100644
--- a/lib/chef_zero/data_store/memory_store.rb
+++ b/lib/chef_zero/data_store/memory_store.rb
@@ -25,7 +25,7 @@ module ChefZero
class MemoryStore < ChefZero::DataStore::V2ToV1Adapter
def initialize
super
- @real_store = ChefZero::DataStore::DefaultFacade.new(ChefZero::DataStore::MemoryStoreV2.new, true)
+ @real_store = ChefZero::DataStore::DefaultFacade.new(ChefZero::DataStore::MemoryStoreV2.new, 'chef', true)
clear
end
end
diff --git a/lib/chef_zero/data_store/memory_store_v2.rb b/lib/chef_zero/data_store/memory_store_v2.rb
index 864d192..9f8b80e 100644
--- a/lib/chef_zero/data_store/memory_store_v2.rb
+++ b/lib/chef_zero/data_store/memory_store_v2.rb
@@ -114,7 +114,7 @@ module ChefZero
begin
value = _get(path)
if value.is_a?(Hash) && !options[:allow_dirs]
- raise "exists? does not work with directories (#{path} = #{dir.class})"
+ raise "exists? does not work with directories (#{path} = #{value.class})"
end
return true
rescue DataNotFoundError
diff --git a/lib/chef_zero/endpoints/acl_base.rb b/lib/chef_zero/endpoints/acl_base.rb
deleted file mode 100644
index ca85590..0000000
--- a/lib/chef_zero/endpoints/acl_base.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require 'json'
-require 'chef_zero/rest_base'
-require 'chef_zero/data_normalizer'
-require 'chef_zero/data_store/default_facade'
-
-module ChefZero
- module Endpoints
- # Extended by AclEndpoint and AclsEndpoint
- class AclBase < RestBase
- def get_acls(request, path)
- acls = get_data(request, acl_path(path))
- acls = JSON.parse(acls, :create_additions => false)
-
- owners = nil
- container_acls = nil
- %w(create read update delete grant).each do |perm|
- acls[perm] ||= {}
- acls[perm]['actors'] ||= begin
- # owners = the superusers (and special case for clients owning themselves)
- owners ||= get_owners(path)
- container_acls ||= get_container_acls(request, path)
- if container_acls
- owners | container_acls[perm]['actors']
- else
- owners
- end
- end
- acls[perm]['groups'] ||= begin
- # When we create containers, we don't merge groups (not sure why).
- if path[0] == 'organizations' && path[2] == 'containers'
- []
- else
- container_acls ||= get_container_acls(request, path)
- container_acls ? container_acls[perm]['groups'] : []
- end
- end
- end
- acls
- end
-
- private
-
- def get_owners(path)
- # The objects that were created with the org itself, and containers for
- # some reason, have the peculiar property of missing superusers from their acls.
- if is_created_with_org?(path, false) || path[0] == 'organizations' && path[2] == 'containers'
- owners = []
- else
- owners = superusers
- # Clients need to be in their own acl list
- if path.size == 4 && path[0] == 'organizations' && path[2] == 'clients'
- owners |= [ path[3] ]
- end
- end
- owners
- end
-
- def get_container_acls(request, path)
- if path[0] == 'organizations'
- if %w(clients cookbooks containers data environments groups nodes roles sandboxes).include?(path[2])
- return get_acls(request, path[0..1] + [ 'containers', path[2] ])
- end
- end
- return nil
- end
-
- def superusers
- data_store.list([ 'superusers' ])
- end
-
- def is_created_with_org?(path, osc_compat = false)
- return false if path.size == 0 || path[0] != 'organizations'
- value = DataStore::DefaultFacade.org_defaults(path[1], 'pivotal', [], osc_compat)
- for part in path[2..-1]
- break if !value
- value = value[part]
- end
- return !!value
- end
- end
- end
-end
diff --git a/lib/chef_zero/endpoints/acl_endpoint.rb b/lib/chef_zero/endpoints/acl_endpoint.rb
index 13a5e6b..e0310c7 100644
--- a/lib/chef_zero/endpoints/acl_endpoint.rb
+++ b/lib/chef_zero/endpoints/acl_endpoint.rb
@@ -1,5 +1,6 @@
require 'json'
-require 'chef_zero/endpoints/acl_base'
+require 'chef_zero/rest_base'
+require 'chef_zero/chef_data/acl_path'
module ChefZero
module Endpoints
@@ -13,14 +14,16 @@ module ChefZero
# /users/NAME/_acl/PERM
#
# Where PERM is create,read,update,delete,grant
- class AclEndpoint < AclBase
+ class AclEndpoint < RestBase
def validate_request(request)
- path = acl_path(request.rest_path[0..-3]) # Strip off _acl/PERM
+ path = request.rest_path[0..-3]
+ path = path[0..1] if path.size == 3 && path[0] == 'organizations' && %w(organization organizations).include?(path[2])
+ acl_path = ChefData::AclPath.get_acl_data_path(path) # Strip off _acl/PERM
perm = request.rest_path[-1]
- if !%w(read create update delete grant).include?(perm)
+ if !acl_path || !%w(read create update delete grant).include?(perm)
raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
end
- [path, perm]
+ [acl_path, perm]
end
def get(request)
diff --git a/lib/chef_zero/endpoints/acls_endpoint.rb b/lib/chef_zero/endpoints/acls_endpoint.rb
index 872ecce..41fb874 100644
--- a/lib/chef_zero/endpoints/acls_endpoint.rb
+++ b/lib/chef_zero/endpoints/acls_endpoint.rb
@@ -1,5 +1,7 @@
require 'json'
-require 'chef_zero/endpoints/acl_base'
+require 'chef_zero/rest_base'
+require 'chef_zero/data_normalizer'
+require 'chef_zero/chef_data/acl_path'
module ChefZero
module Endpoints
@@ -10,11 +12,16 @@ module ChefZero
# or
# /organizations/ORG/organization/_acl
# /users/NAME/_acl
- class AclsEndpoint < AclBase
+ class AclsEndpoint < RestBase
def get(request)
path = request.rest_path[0..-2] # Strip off _acl
- path = path[0..1] if path.size == 3 && path[0] == 'organizations' && path[2] == 'organizations'
- acls = DataNormalizer.normalize_acls(get_acls(request, path))
+ path = path[0..1] if path.size == 3 && path[0] == 'organizations' && %w(organization organizations).include?(path[2])
+ acl_path = ChefData::AclPath.get_acl_data_path(path)
+ if !acl_path
+ 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)
json_response(200, acls)
end
diff --git a/lib/chef_zero/endpoints/cookbook_version_endpoint.rb b/lib/chef_zero/endpoints/cookbook_version_endpoint.rb
index a3ac7b4..098c6c6 100644
--- a/lib/chef_zero/endpoints/cookbook_version_endpoint.rb
+++ b/lib/chef_zero/endpoints/cookbook_version_endpoint.rb
@@ -62,7 +62,6 @@ module ChefZero
cookbook_path = request.rest_path[0..1] + ['cookbooks', cookbook_name]
if exists_data_dir?(request, cookbook_path) && list_data(request, cookbook_path).size == 0
delete_data_dir(request, cookbook_path)
- delete_acl(cookbook_path)
end
# Hoover deleted files, if they exist
@@ -98,7 +97,7 @@ module ChefZero
# This deals with an exception on delete, but things can still get deleted
# that shouldn't be.
begin
- data_store.delete(request.rest_path[0..1] + ['file_store', 'checksums', checksum])
+ delete_data(request, request.rest_path[0..1] + ['file_store', 'checksums', checksum], :data_store_exceptions)
rescue ChefZero::DataStore::DataNotFoundError
end
end
diff --git a/lib/chef_zero/endpoints/data_bag_endpoint.rb b/lib/chef_zero/endpoints/data_bag_endpoint.rb
index ce7e263..41e87ae 100644
--- a/lib/chef_zero/endpoints/data_bag_endpoint.rb
+++ b/lib/chef_zero/endpoints/data_bag_endpoint.rb
@@ -34,7 +34,6 @@ module ChefZero
def delete(request)
key = request.rest_path[3]
delete_data_dir(request, request.rest_path, :recursive)
- delete_acl(request.rest_path)
json_response(200, {
'chef_type' => 'data_bag',
'json_class' => 'Chef::DataBag',
diff --git a/lib/chef_zero/endpoints/data_bags_endpoint.rb b/lib/chef_zero/endpoints/data_bags_endpoint.rb
index c3e5970..732c1a5 100644
--- a/lib/chef_zero/endpoints/data_bags_endpoint.rb
+++ b/lib/chef_zero/endpoints/data_bags_endpoint.rb
@@ -14,7 +14,7 @@ module ChefZero
elsif exists_data_dir?(request, request.rest_path[0..1] + ['data', name])
error(409, "Object already exists")
else
- data_store.create_dir(request.rest_path[0..1] + ['data'], name, :recursive)
+ create_data_dir(request, 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/rest_object_endpoint.rb b/lib/chef_zero/endpoints/rest_object_endpoint.rb
index 5947d6d..fb821e0 100644
--- a/lib/chef_zero/endpoints/rest_object_endpoint.rb
+++ b/lib/chef_zero/endpoints/rest_object_endpoint.rb
@@ -28,7 +28,7 @@ module ChefZero
rename = key != request.rest_path[-1]
if rename
begin
- data_store.create(request.rest_path[0..1] + request.rest_path[2..-2], key, request.body)
+ create_data(request, request.rest_path[0..1] + request.rest_path[2..-2], key, request.body, :data_store_exceptions)
rescue DataStore::DataAlreadyExistsError
return error(409, "Cannot rename '#{request.rest_path[-1]}' to '#{key}': '#{key}' already exists")
end
@@ -43,7 +43,6 @@ module ChefZero
def delete(request)
result = get_data(request)
delete_data(request)
- delete_acl(request.rest_path)
already_json_response(200, populate_defaults(request, result))
end
diff --git a/lib/chef_zero/rest_base.rb b/lib/chef_zero/rest_base.rb
index 5d44322..f64343b 100644
--- a/lib/chef_zero/rest_base.rb
+++ b/lib/chef_zero/rest_base.rb
@@ -1,6 +1,7 @@
require 'chef_zero/rest_request'
require 'chef_zero/rest_error_response'
require 'chef_zero/data_store/data_not_found_error'
+require 'chef_zero/chef_data/acl_path'
module ChefZero
class RestBase
@@ -52,27 +53,43 @@ module ChefZero
rescue DataStore::DataNotFoundError
if options.include?(:nil)
nil
+ elsif options.include?(:data_store_exceptions)
+ raise
else
raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
end
end
end
- def list_data(request, rest_path=nil)
+ def list_data(request, rest_path=nil, *options)
rest_path ||= request.rest_path
begin
data_store.list(rest_path)
rescue DataStore::DataNotFoundError
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
+ end
end
end
- def delete_data(request, rest_path=nil)
+ def delete_data(request, rest_path=nil, *options)
rest_path ||= request.rest_path
begin
- data_store.delete(rest_path)
+ data_store.delete(rest_path, *options)
+ rescue DataStore::DataNotFoundError
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ end
+ end
+
+ begin
+ acl_path = ChefData::AclPath.get_acl_data_path(rest_path)
+ data_store.delete(acl_path) if acl_path
rescue DataStore::DataNotFoundError
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
end
end
@@ -81,7 +98,17 @@ module ChefZero
begin
data_store.delete_dir(rest_path, *options)
rescue DataStore::DataNotFoundError
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ end
+ end
+
+ begin
+ acl_path = ChefData::AclPath.get_acl_data_path(rest_path)
+ data_store.delete(acl_path) if acl_path
+ rescue DataStore::DataNotFoundError
end
end
@@ -90,29 +117,49 @@ module ChefZero
begin
data_store.set(rest_path, data, *options)
rescue DataStore::DataNotFoundError
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ end
end
end
def create_data_dir(request, rest_path, name, *options)
rest_path ||= request.rest_path
begin
- data_store.create_dir(rest_path, name, *options)
+ data_store.create_dir(rest_path, name, *options, :requestor => request.requestor)
rescue DataStore::DataNotFoundError
- raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
+ end
rescue DataStore::DataAlreadyExistsError
- raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
+ end
end
end
def create_data(request, rest_path, name, data, *options)
rest_path ||= request.rest_path
begin
- data_store.create(rest_path, name, data, *options)
+ data_store.create(rest_path, name, data, *options, :requestor => request.requestor)
rescue DataStore::DataNotFoundError
- raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
+ end
rescue DataStore::DataAlreadyExistsError
- raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
+ if options.include?(:data_store_exceptions)
+ raise
+ else
+ raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
+ end
end
end
@@ -158,33 +205,5 @@ module ChefZero
def populate_defaults(request, response)
response
end
-
- def delete_acl(path)
- # On delete we have to delete the corresponding acl
- acl = acl_path(path)
- if acl
- begin
- data_store.delete(acl)
- rescue DataStore::DataNotFoundError
- end
- end
- end
-
- def acl_path(path)
- if path[0] == 'organizations' && path.size > 2
- if path.size == 4
- acl_path = path[0..1] + [ 'acls' ] + path[2..3]
- elsif path.size == 3 && %w(organization organizations).include?(path[2])
- acl_path = path[0..1] + [ 'acls', path[2] ]
- elsif path.size == 3
- acl_path = path[0..1] + [ 'acls', 'containers', path[2] ]
- end
- elsif path[0] == 'organizations' && path.size == 2
- acl_path = path + %w(acls organizations)
- else
- acl_path = [ 'acls' ] + path
- end
- acl_path
- end
end
end
diff --git a/lib/chef_zero/rest_error_response.rb b/lib/chef_zero/rest_error_response.rb
index 2edca25..e75d427 100644
--- a/lib/chef_zero/rest_error_response.rb
+++ b/lib/chef_zero/rest_error_response.rb
@@ -1,5 +1,5 @@
module ChefZero
- class RestErrorResponse < Exception
+ class RestErrorResponse < StandardError
def initialize(response_code, error)
@response_code = response_code
@error = error
diff --git a/lib/chef_zero/server.rb b/lib/chef_zero/server.rb
index 03d196b..c952278 100644
--- a/lib/chef_zero/server.rb
+++ b/lib/chef_zero/server.rb
@@ -145,12 +145,12 @@ module ChefZero
#
def data_store
@data_store ||= begin
- result = @options[:data_store] || DataStore::DefaultFacade.new(DataStore::MemoryStoreV2.new, options[:osc_compat])
+ result = @options[:data_store] || DataStore::DefaultFacade.new(DataStore::MemoryStoreV2.new, options[:single_org], options[:osc_compat])
if options[:single_org]
if !result.respond_to?(:interface_version) || result.interface_version == 1
result = ChefZero::DataStore::V1ToV2Adapter.new(result, options[:single_org])
- result = ChefZero::DataStore::DefaultFacade.new(result, options[:osc_compat])
+ result = ChefZero::DataStore::DefaultFacade.new(result, options[:single_org], options[:osc_compat])
end
else
@@ -393,9 +393,6 @@ module ChefZero
def clear_data
data_store.clear
- if options[:single_org]
- data_store.create_dir([ 'organizations' ], options[:single_org])
- end
end
def request_handler(&block)