class Chef::ChefFS::ChefFSDataStore
Translation layer between chef-zero’s DataStore (a place where it expects files to be stored) and ChefFS
(the user’s repository directory layout).
chef-zero expects the data store to store files its way–for example, it expects get(“nodes/blah”) to return the JSON text for the blah node, and it expects get(“cookbooks/blah/1.0.0”) to return the JSON definition of the blah cookbook version 1.0.0.
The repository is defined the way the user wants their layout. These two things are very similar in layout (for example, nodes are stored under the nodes/ directory and their filename is the name of the node).
However, there are a few differences that make this more than just a raw file store:
-
Cookbooks are stored much differently.
- chef-zero places JSON text with the checksums for the cookbook at /cookbooks/NAME/VERSION, and expects the JSON to contain URLs to the actual files, which are stored elsewhere. - The repository contains an actual directory with just the cookbook files and a metadata.rb containing a version #. There is no JSON to be found. - Further, if versioned_cookbooks is false, that directory is named /cookbooks/NAME and only one version exists. If versioned_cookbooks is true, the directory is named /cookbooks/NAME-VERSION. - Therefore, ChefFSDataStore calculates the cookbook JSON by looking at the files in the cookbook and checksumming them, and reading metadata.rb for the version and dependency information. - ChefFSDataStore also modifies the cookbook file URLs so that they point to /file_store/repo/<filename> (the path to the actual file under the repository root). For example, /file_store/repo/apache2/metadata.rb or /file_store/repo/cookbooks/apache2/recipes/default.rb).
-
Sandboxes don’t exist in the repository.
- ChefFSDataStore lets cookbooks be uploaded into a temporary memory storage, and when the cookbook is committed, copies the files onto the disk in the correct place (/cookbooks/apache2/recipes/default.rb).
-
Data bags:
- The Chef server expects data bags in /data/BAG/ITEM - The repository stores data bags in /data_bags/BAG/ITEM
-
JSON filenames are generally NAME.json in the repository (e.g. /nodes/foo.json).
-
Org
membership: chef-zero stores user membership in an org as a series of empty files. If an org has jkeiser and cdoherty as members, chef-zero expects these files to exist:-
‘users/jkeiser` (content: ’{}‘)
-
‘users/cdoherty` (content: ’{}‘)
ChefFS
, on the other hand, stores user membership in an org as a single file, ‘members.json`, with content:```json [ { "user": { "username": "jkeiser" } }, { "user": { "username": "cdoherty" } } ] ```
To translate between the two, we need to intercept requests to ‘users` like so:
-
‘list(users)` -> `get(/members.json)`
-
‘get(users/NAME)` -> `get(/members.json)`, see if it’s in there
-
‘create(users/NAME)` -> `get(/members.json)`, add name, `set(/members.json)`
-
‘delete(users/NAME)` -> `get(/members.json)`, remove name, `set(/members.json)`
-
-
Org
invitations: chef-zero stores org membership invitations as a series of empty files. If an org has invited jkeiser and cdoherty (and they have not yet accepted the invite), chef-zero expects these files to exist:-
‘association_requests/jkeiser` (content: ’{}‘)
-
‘association_requests/cdoherty` (content: ’{}‘)
ChefFS
, on the other hand, stores invitations as a single file, ‘invitations.json`, with content:```json [ { "id" => "jkeiser-chef", 'username' => 'jkeiser' }, { "id" => "cdoherty-chef", 'username' => 'cdoherty' } ] ```
To translate between the two, we need to intercept requests to ‘users` like so:
-
‘list(association_requests)` -> `get(/invitations.json)`
-
‘get(association_requests/NAME)` -> `get(/invitations.json)`, see if it’s in there
-
‘create(association_requests/NAME)` -> `get(/invitations.json)`, add name, `set(/invitations.json)`
-
‘delete(association_requests/NAME)` -> `get(/invitations.json)`, remove name, `set(/invitations.json)`
-
Constants
- BASE_DIRNAMES
-
The base directories in a
Chef
Repo; even when these don’t exist, a matching GET for these objects will return an empty list instead of a 404.
Attributes
Public Class Methods
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 157 def initialize(chef_fs, chef_config = Chef::Config) @chef_fs = chef_fs @memory_store = ChefZero::DataStore::MemoryStore.new @repo_mode = chef_config[:repo_mode] end
Create a new ChefFSDataStore
Arguments¶ ↑
chef_fs
-
A
ChefFS::FileSystem
object representing the repository root. Generally will be aChefFS::FileSystem::ChefRepositoryFileSystemRoot
object, created fromChefFS::Config.local_fs
.
Public Instance Methods
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 202 def create(path, name, data, *options) if use_memory_store?(path) @memory_store.create(path, name, data, *options) 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.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", [], *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) end # Actually add the user members << { "user" => { "username" => name } } end # 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", [], *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) end # Actually add the user (TODO insert org name??) invitations << { "username" => name } end else unless data.is_a?(String) raise "set only works with strings" end with_parent_dir(path + [name], *options) do |parent, name| parent.create_child(name, data) rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e) end end end
If you want to get the contents of /data/x/y from the server, you say chef_fs.child(‘data’).child(‘x’).child(‘y’).read. It will make exactly one network request: GET /data/x/y And that will return 404 if it doesn’t exist.
ChefFS
objects do not go to the network until you ask them for data. This means you can construct a /data/x/y ChefFS
entry early.
Alternative: chef_fs.child(‘data’) could have done a GET /data preemptively, allowing it to know whether child(‘x’) was valid (GET /data gives you a list of data bags). Then child(‘x’) could have done a GET /data/x, allowing it to know whether child(‘y’) (the item) existed. Finally, we would do the GET /data/x/y to read the contents. Three network requests instead of 1.
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 170 def create_dir(path, name, *options) if use_memory_store?(path) @memory_store.create_dir(path, name, *options) else with_parent_dir(path + [name], *options) do |parent, name| parent.create_child(name, nil) rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e) end end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 395 def delete(path) 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"].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 update_json("members.json", []) do |members| result = members.reject { |member| member["user"]["username"] == path[1] } if result.size == members.size raise ChefZero::DataStore::DataNotFoundError.new(path) end result end # DELETE [/organizations/ORG]/users/NAME # Manipulates members.json elsif is_org? && path[0] == "association_requests" && path.length == 2 update_json("invitations.json", []) do |invitations| result = invitations.reject { |invitation| invitation["username"] == path[1] } if result.size == invitations.size raise ChefZero::DataStore::DataNotFoundError.new(path) end result end else with_entry(path) do |entry| if %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length >= 3 entry.delete(true) else entry.delete(false) end rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 449 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) FileSystemCache.instance.delete!(policy.file_path) found_policy = true end raise ChefZero::DataStore::DataNotFoundError.new(path) unless found_policy end else with_entry(path) do |entry| entry.delete(options.include?(:recursive)) rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 584 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"].key?(path[3]) else path_always_exists?(path) || Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists? end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 598 def exists_dir?(path) if use_memory_store?(path) @memory_store.exists_dir?(path) elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && 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]) else Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists? end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 263 def get(path, request = nil) if use_memory_store?(path) @memory_store.get(path) elsif path[0] == "file_store" && path[1] == "repo" entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[2..].join("/")) begin entry.read rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end # /policy_groups/NAME/policies/POLICYNAME: return the revision of the given policy elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4 # 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 elsif is_org? && path[0] == "users" && path.length == 2 if get_json("members.json", []).any? { |member| member["user"]["username"] == path[1] } "{}" else raise ChefZero::DataStore::DataNotFoundError.new(path) end # GET [/organizations/ORG]/association_requests/NAME -> /users/NAME # Manipulates invites.json elsif is_org? && path[0] == "association_requests" && path.length == 2 if get_json("invites.json", []).any? { |member| member["user"]["username"] == path[1] } "{}" else raise ChefZero::DataStore::DataNotFoundError.new(path) end # GET /cookbooks/NAME/VERSION or /cookbook_artifacts/NAME/IDENTIFIER elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 3 with_entry(path) do |entry| cookbook_type = path[0] result = nil begin result = Chef::CookbookManifest.new(entry.chef_object, policy_mode: cookbook_type == "cookbook_artifacts").to_h rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end result.each_pair do |key, value| if value.is_a?(Array) value.each do |file| if file.is_a?(Hash) && file.key?("checksum") relative = ["file_store", "repo", cookbook_type] if chef_fs.versioned_cookbooks || cookbook_type == "cookbook_artifacts" relative << "#{path[1]}-#{path[2]}" else relative << path[1] end relative += file[:path].split("/") file["url"] = ChefZero::RestBase.build_uri(request.base_uri, relative) end end end end if cookbook_type == "cookbook_artifacts" result["metadata"] = result["metadata"].to_h result["metadata"].delete_if do |key, value| value == [] || (value == {} && !%w{dependencies attributes recipes}.include?(key)) || (value == "" && %w{source_url issues_url}.include?(key)) || (value == false && key == "privacy") end end Chef::JSONCompat.to_json_pretty(result) end else with_entry(path) do |entry| entry.read rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 483 def list(path) 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 rescue Chef::ChefFS::FileSystem::NotFoundError [] 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(path[0..1]) do |entry| policies = Chef::JSONCompat.parse(entry.read)["policies"] || {} policies.keys end elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 1 with_entry(path) do |entry| if path[0] == "cookbook_artifacts" entry.children.map { |child| child.name.rpartition("-")[0] }.uniq elsif chef_fs.versioned_cookbooks # /cookbooks/name-version -> /cookbooks/name entry.children.map { |child| split_name_version(child.name)[0] }.uniq else entry.children.map(&:name) end rescue Chef::ChefFS::FileSystem::NotFoundError # If the cookbooks dir doesn't exist, we have no cookbooks (not 404) [] end elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 2 if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts" result = with_entry([ path[0] ]) do |entry| # list /cookbooks/name = filter /cookbooks/name-version down to name entry.children.map { |child| split_name_version(child.name) } .select { |name, version| name == path[1] } .map { |name, version| version } end if result.empty? raise ChefZero::DataStore::DataNotFoundError.new(path) end result else # list /cookbooks/name = <single version> version = get_single_cookbook_version(path) [version] end else result = with_entry(path) do |entry| entry.children.map { |c| zero_filename(c) }.sort rescue Chef::ChefFS::FileSystem::NotFoundError => e # /cookbooks, /data, etc. never return 404 if path_always_exists?(path) [] else raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end end # Older versions of chef-zero do not understand policies and cookbook_artifacts, # don't give that stuff to them if path == [] && ChefZero::VERSION.to_f < 4.4 result.reject! { |child| %w{policies policy_data cookbook_artifacts}.include?(child) } end result end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 163 def publish_description "Reading and writing data to #{chef_fs.fs_description}" end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 361 def set(path, data, *options) if use_memory_store?(path) @memory_store.set(path, data, *options) else unless data.is_a?(String) raise "set only works with strings: #{path} = #{data.inspect}" end # Write out the files! if %w{cookbooks cookbook_artifacts}.include?(path[0]) && 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_parent_dir(path, *options) do |parent, name| child = parent.child(name) if child.exists? child.write(data) else parent.create_child(name, data) end end end end end
Private Instance Methods
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 673 def _to_chef_fs_path(path) path = path.dup # /data -> /data_bags # /data/BAG -> /data_bags/BAG # /data/BAG/ITEM -> /data_bags/BAG/ITEM.json if path[0] == "data" path[0] = "data_bags" if path.length >= 3 path[2] = "#{path[2]}.json" end # /client_keys/CLIENT/keys -> /client_keys/CLIENT # /client_keys/CLIENT/keys/KEYNAME -> /client_keys/CLIENT/KEYNAME.json elsif path[0] == "client_keys" path.delete_at(2) if path.length >= 3 path[-1] += ".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 %w{cookbooks cookbook_artifacts}.include?(path[0]) if path.length == 2 raise ChefZero::DataStore::DataNotFoundError.new(path) elsif path.length >= 3 if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts" # cookbooks/name/version -> cookbooks/name-version path = [ path[0], "#{path[1]}-#{path[2]}" ] + path[3..-1] else # cookbooks/name/version/... -> /cookbooks/name/... iff metadata says so version = get_single_cookbook_version(path) if path[2] == version path = path[0..1] + path[3..-1] else raise ChefZero::DataStore::DataNotFoundError.new(path) end end end elsif path[0] == "acls" # /acls/data -> /acls/data_bags if path[1] == "data" path[1] = "data_bags" end # /acls/containers|nodes|.../x.json # /acls/organization.json if path.length == 3 || path == %w{acls organization} path[-1] = "#{path[-1]}.json" end # /acls/containers|nodes|... do NOT drop into the next elsif, and do # not get .json appended # /nodes|clients|.../x.json elsif path.length == 2 path[-1] = "#{path[-1]}.json" end path end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 669 def chef_fs_filename(path) _to_chef_fs_path(path)[-1] end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 854 def ensure_dir(entry) return entry if entry.exists? parent = entry.parent if parent ensure_dir(parent) parent.create_child(entry.name) end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 822 def get_dir(path, create = false) result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join("/")) if result.exists? result elsif create || path.size == 1 get_dir(path[0..-2], create).create_child(result.name, nil) else raise ChefZero::DataStore::DataNotFoundError.new(path) end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 864 def get_json(path, default_value) entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path) begin Chef::JSONCompat.parse(entry.read) rescue Chef::ChefFS::FileSystem::NotFoundError default_value end end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 833 def get_single_cookbook_version(path) dir = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join("/")) metadata = ChefZero::CookbookData.metadata_from(dir, path[1], nil, []) metadata[:version] || "0.0.0" end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 873 def is_org? repo_mode == "hosted_everything" end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 788 def path_always_exists?(path) path.length == 1 && BASE_DIRNAMES.include?(path[0]) end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 658 def split_name_version(entry_name) name_version = entry_name.split("-") name = name_version[0..-2].join("-") version = name_version[-1] [name, version] end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 665 def to_chef_fs_path(path) _to_chef_fs_path(path).join("/") end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 737 def to_zero_path(entry) path = entry.path.split("/")[1..-1] if path[0] == "data_bags" path[0] = "data" if path.length >= 3 path[2] = path[2][0..-6] end # /client_keys/CLIENT -> /client_keys/CLIENT/keys # /client_keys/CLIENT/KEYNAME.json -> /client_keys/CLIENT/keys/KEYNAME elsif path[0] == "client_keys" if path.size == 2 path << "keys" elsif path.size > 2 path[2..-1] = [ "keys", path[-1][0..-6] ] end elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts" # cookbooks/name-version/... -> cookbooks/name/version/... if path.length >= 2 name, version = split_name_version(path[1]) path = [ path[0], name, version ] + path[2..-1] end else if path.length >= 2 # cookbooks/name/... -> cookbooks/name/version/... version = get_single_cookbook_version(path) path = path[0..1] + [version] + path[2..-1] 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[1] = path[1].gsub(/\.(rb|json)$/, "") end path end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 839 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 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 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
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 620 def use_memory_store?(path) path[0] == "sandboxes" || path[0] == "file_store" && path[1] == "checksums" || path == %w{environments _default} end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 809 def with_dir(path) # Do not automatically create data bags create = !(path[0] == "data" && path.size >= 2) begin yield get_dir(_to_chef_fs_path(path), create) 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
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 792 def with_entry(path) yield Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)) rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 798 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
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 624 def write_cookbook(path, data, *options) cookbook_type = path[0] if chef_fs.versioned_cookbooks cookbook_path = File.join(cookbook_type, "#{path[1]}-#{path[2]}") else cookbook_path = File.join(cookbook_type, path[1]) end # Create a little Chef::ChefFS memory filesystem with the data cookbook_fs = Chef::ChefFS::FileSystem::Memory::MemoryRoot.new("uploading") cookbook = Chef::JSONCompat.parse(data) cookbook.each_pair do |key, value| if value.is_a?(Array) value.each do |file| if file.is_a?(Hash) && file.key?("checksum") file_data = @memory_store.get(["file_store", "checksums", file["checksum"]]) cookbook_fs.add_file(File.join(cookbook_path, file["path"]), file_data) end end end end # Create the .uploaded-cookbook-version.json cookbooks = chef_fs.child(cookbook_type) unless cookbooks.exists? cookbooks = chef_fs.create_child(cookbook_type) end # We are calling a cookbooks-specific API, so get multiplexed_dirs out of the way if it is there if cookbooks.respond_to?(:multiplexed_dirs) cookbooks = cookbooks.write_dir end cookbooks.write_cookbook(cookbook_path, data, cookbook_fs) end
Source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 784 def zero_filename(entry) to_zero_path(entry)[-1] end