class Chef::ChefFS::ChefFSDataStore

Attributes

chef_fs[R]

Public Class Methods

new(chef_fs) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 31
def initialize(chef_fs)
  @chef_fs = chef_fs
  @memory_store = ChefZero::DataStore::MemoryStore.new
end

Public Instance Methods

create(path, name, data, *options) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 56
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.

  else
    if !data.is_a?(String)
      raise "set only works with strings"
    end

    with_dir(path) do |parent|
      begin
        parent.create_child(chef_fs_filename(path + [name]), data)
      rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
        raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
      end
    end
  end
end
create_dir(path, name, *options) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 42
def create_dir(path, name, *options)
  if use_memory_store?(path)
    @memory_store.create_dir(path, name, *options)
  else
    with_dir(path) do |parent|
      begin
        parent.create_child(chef_fs_filename(path + [name]), nil)
      rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
        raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
      end
    end
  end
end
delete(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 154
def delete(path)
  if use_memory_store?(path)
    @memory_store.delete(path)
  else
    with_entry(path) do |entry|
      begin
        if path[0] == 'cookbooks' && 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
end
delete_dir(path, *options) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 172
def delete_dir(path, *options)
  if use_memory_store?(path)
    @memory_store.delete_dir(path, *options)
  else
    with_entry(path) do |entry|
      begin
        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
end
exists?(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 239
def exists?(path)
  if use_memory_store?(path)
    @memory_store.exists?(path)
  else
    path_always_exists?(path) || Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
  end
end
exists_dir?(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 247
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])
  else
    Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
  end
end
get(path, request=nil) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 78
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..-1].join('/'))
    begin
      entry.read
    rescue Chef::ChefFS::FileSystem::NotFoundError => e
      raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
    end

  else
    with_entry(path) do |entry|
      if path[0] == 'cookbooks' && path.length == 3
        # get /cookbooks/NAME/version
        result = nil
        begin
          result = entry.chef_object.to_hash
        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.has_key?('checksum')
                relative = ['file_store', 'repo', 'cookbooks']
                if Chef::Config.versioned_cookbooks
                  relative << "#{path[1]}-#{path[2]}"
                else
                  relative << path[1]
                end
                relative = relative + file[:path].split('/')
                file['url'] = ChefZero::RestBase::build_uri(request.base_uri, relative)
              end
            end
          end
        end
        JSON.pretty_generate(result)

      else
        begin
          entry.read
        rescue Chef::ChefFS::FileSystem::NotFoundError => e
          raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
        end
      end
    end
  end
end
list(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 186
def list(path)
  if use_memory_store?(path)
    @memory_store.list(path)

  elsif path[0] == 'cookbooks' && path.length == 1
    with_entry(path) do |entry|
      begin
        if Chef::Config.versioned_cookbooks
          # /cookbooks/name-version -> /cookbooks/name
          entry.children.map { |child| split_name_version(child.name)[0] }.uniq
        else
          entry.children.map { |child| child.name }
        end
      rescue Chef::ChefFS::FileSystem::NotFoundError
        # If the cookbooks dir doesn't exist, we have no cookbooks (not 404)
        []
      end
    end

  elsif path[0] == 'cookbooks' && path.length == 2
    if Chef::Config.versioned_cookbooks
      result = with_entry([ 'cookbooks' ]) 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
    with_entry(path) do |entry|
      begin
        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
    end
  end
end
publish_description() click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 36
def publish_description
  "Reading and writing data to #{chef_fs.fs_description}"
end
set(path, data, *options) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 130
def set(path, data, *options)
  if use_memory_store?(path)
    @memory_store.set(path, data, *options)
  else
    if !data.is_a?(String)
      raise "set only works with strings: #{path} = #{data.inspect}"
    end

    # Write out the files!
    if path[0] == 'cookbooks' && path.length == 3
      write_cookbook(path, data, *options)
    else
      with_dir(path[0..-2]) do |parent|
        child = parent.child(chef_fs_filename(path))
        if child.exists?
          child.write(data)
        else
          parent.create_child(chef_fs_filename(path), data)
        end
      end
    end
  end
end

Private Instance Methods

_to_chef_fs_path(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 311
def _to_chef_fs_path(path)
  if path[0] == 'data'
    path = path.dup
    path[0] = 'data_bags'
    if path.length >= 3
      path[2] = "#{path[2]}.json"
    end
  elsif path[0] == 'cookbooks'
    if path.length == 2
      raise ChefZero::DataStore::DataNotFoundError.new(path)
    elsif Chef::Config.versioned_cookbooks
      if path.length >= 3
        # cookbooks/name/version -> cookbooks/name-version
        path = [ path[0], "#{path[1]}-#{path[2]}" ] + path[3..-1]
      end
    else
      if path.length >= 3
        # 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.length == 2
    path = path.dup
    path[1] = "#{path[1]}.json"
  end
  path
end
chef_fs_filename(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 307
def chef_fs_filename(path)
  _to_chef_fs_path(path)[-1]
end
get_dir(path, create=false) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 401
def get_dir(path, create=false)
  result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join('/'))
  if result.exists?
    result
  elsif create
    get_dir(path[0..-2], create).create_child(result.name, nil)
  else
    raise ChefZero::DataStore::DataNotFoundError.new(path)
  end
end
get_single_cookbook_version(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 412
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
path_always_exists?(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 379
def path_always_exists?(path)
  return path.length == 1 && %w(clients cookbooks data environments nodes roles users).include?(path[0])
end
split_name_version(entry_name) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 296
def split_name_version(entry_name)
  name_version = entry_name.split('-')
  name = name_version[0..-2].join('-')
  version = name_version[-1]
  [name,version]
end
to_chef_fs_path(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 303
def to_chef_fs_path(path)
  _to_chef_fs_path(path).join('/')
end
to_zero_path(entry) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 344
def to_zero_path(entry)
  path = entry.path.split('/')[1..-1]
  if path[0] == 'data_bags'
    path = path.dup
    path[0] = 'data'
    if path.length >= 3
      path[2] = path[2][0..-6]
    end

  elsif path[0] == 'cookbooks'
    if Chef::Config.versioned_cookbooks
      # 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

  elsif path.length == 2 && path[0] != 'cookbooks'
    path = path.dup
    path[1] = path[1][0..-6]
  end
  path
end
use_memory_store?(path) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 259
def use_memory_store?(path)
  return path[0] == 'sandboxes' || path[0] == 'file_store' && path[1] == 'checksums' || path == [ 'environments', '_default' ]
end
with_dir(path) { |get_dir(_to_chef_fs_path(path), create)| ... } click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 391
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
    raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
  end
end
with_entry(path) { |resolve_path(chef_fs, to_chef_fs_path(path))| ... } click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 383
def with_entry(path)
  begin
    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
end
write_cookbook(path, data, *options) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 263
def write_cookbook(path, data, *options)
  if Chef::Config.versioned_cookbooks
    cookbook_path = File.join('cookbooks', "#{path[1]}-#{path[2]}")
  else
    cookbook_path = File.join('cookbooks', path[1])
  end

  # Create a little Chef::ChefFS memory filesystem with the data
  cookbook_fs = Chef::ChefFS::FileSystem::MemoryRoot.new('uploading')
  cookbook = JSON.parse(data, :create_additions => false)
  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_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('cookbooks')
  if !cookbooks.exists?
    cookbooks = chef_fs.create_child('cookbooks')
  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
zero_filename(entry) click to toggle source
# File lib/chef/chef_fs/chef_fs_data_store.rb, line 375
def zero_filename(entry)
  to_zero_path(entry)[-1]
end