Class/Module Index [+]

Quicksearch

Chef::Provider::File

Public Instance Methods

action_create() click to toggle source
# File lib/chef/provider/file.rb, line 244
def action_create
  if !::File.exists?(@new_resource.path)
    description = []
    desc = "create new file #{@new_resource.path}"
    desc << " with content checksum #{short_cksum(new_resource_content_checksum)}" if new_resource.content
    description << desc
    description << diff_current_from_content(@new_resource.content) 
    
    converge_by(description) do
      Chef::Log.info("entered create")
      ::File.open(@new_resource.path, "w+") {|f| f.write @new_resource.content }
      access_controls.set_all
      Chef::Log.info("#{@new_resource} created file #{@new_resource.path}")
      update_new_file_state
    end
  else
    set_content unless @new_resource.content.nil?
    set_all_access_controls
  end
end
action_create_if_missing() click to toggle source
# File lib/chef/provider/file.rb, line 275
def action_create_if_missing
  if ::File.exists?(@new_resource.path)
    Chef::Log.debug("#{@new_resource} exists at #{@new_resource.path} taking no action.")
  else
    action_create
  end
end
action_delete() click to toggle source
# File lib/chef/provider/file.rb, line 283
def action_delete
  if ::File.exists?(@new_resource.path)
    converge_by("delete file #{@new_resource.path}") do 
      backup unless ::File.symlink?(@new_resource.path)
      ::File.delete(@new_resource.path)
      Chef::Log.info("#{@new_resource} deleted file at #{@new_resource.path}")
    end
  end
end
action_touch() click to toggle source
# File lib/chef/provider/file.rb, line 293
def action_touch
  action_create
  converge_by("update utime on file #{@new_resource.path}") do
    time = Time.now
    ::File.utime(time, time, @new_resource.path)
    Chef::Log.info("#{@new_resource} updated atime and mtime to #{time}")
  end
end
backup(file=nil) click to toggle source
# File lib/chef/provider/file.rb, line 302
def backup(file=nil)
  file ||= @new_resource.path
  if @new_resource.backup != false && @new_resource.backup > 0 && ::File.exist?(file)
    time = Time.now
    savetime = time.strftime("%Y%m%d%H%M%S")
    backup_filename = "#{@new_resource.path}.chef-#{savetime}"
    backup_filename = backup_filename.sub(/^([A-Za-z]:)/, "") #strip drive letter on Windows
    # if :file_backup_path is nil, we fallback to the old behavior of
    # keeping the backup in the same directory. We also need to to_s it
    # so we don't get a type error around implicit to_str conversions.
    prefix = Chef::Config[:file_backup_path].to_s
    backup_path = ::File.join(prefix, backup_filename)
    FileUtils.mkdir_p(::File.dirname(backup_path)) if Chef::Config[:file_backup_path]
    FileUtils.cp(file, backup_path, :preserve => true)
    Chef::Log.info("#{@new_resource} backed up to #{backup_path}")

    # Clean up after the number of backups
    slice_number = @new_resource.backup
    backup_files = Dir[::File.join(prefix, ".#{@new_resource.path}.chef-*")].sort { |a,b| b <=> a }
    if backup_files.length >= @new_resource.backup
      remainder = backup_files.slice(slice_number..-1)
      remainder.each do |backup_to_delete|
        FileUtils.rm(backup_to_delete)
        Chef::Log.info("#{@new_resource} removed backup at #{backup_to_delete}")
      end
    end
  end
end
compare_content() click to toggle source

Compare the content of a file. Returns true if they are the same, false if they are not.

# File lib/chef/provider/file.rb, line 205
def compare_content
  checksum(@current_resource.path) == new_resource_content_checksum
end
define_resource_requirements() click to toggle source
# File lib/chef/provider/file.rb, line 177
def define_resource_requirements
  # this must be evaluated before whyrun messages are printed
  access_controls.requires_changes?

  requirements.assert(:create, :create_if_missing, :touch) do |a|
    # Make sure the parent dir exists, or else fail.
    # for why run, print a message explaining the potential error.
    parent_directory = ::File.dirname(@new_resource.path)

    a.assertion { ::File.directory?(parent_directory) }
    a.failure_message(Chef::Exceptions::EnclosingDirectoryDoesNotExist, "Parent directory #{parent_directory} does not exist.")
    a.whyrun("Assuming directory #{parent_directory} would have been created")
  end

  # Make sure the file is deletable if it exists. Otherwise, fail.
  requirements.assert(:delete) do |a|
    a.assertion do
      if ::File.exists?(@new_resource.path) 
        ::File.writable?(@new_resource.path)
      else
        true
      end
    end
    a.failure_message(Chef::Exceptions::InsufficientPermissions,"File #{@new_resource.path} exists but is not writable so it cannot be deleted")
  end
end
deploy_tempfile() click to toggle source
# File lib/chef/provider/file.rb, line 331
def deploy_tempfile
  Tempfile.open(::File.basename(@new_resource.name)) do |tempfile|
    yield tempfile

    temp_res = Chef::Resource::CookbookFile.new(@new_resource.name)
    temp_res.path(tempfile.path)
    ac = Chef::FileAccessControl.new(temp_res, @new_resource, self)
    ac.set_all!
    FileUtils.mv(tempfile.path, @new_resource.path)
  end
end
diff_current(temp_path) click to toggle source
# File lib/chef/provider/file.rb, line 69
def diff_current(temp_path)
  suppress_resource_reporting = false

  return [ "(diff output suppressed by config)" ] if Chef::Config[:diff_disabled]
  return [ "(no temp file with new content, diff output suppressed)" ] unless ::File.exists?(temp_path)  # should never happen?

  # solaris does not support diff -N, so create tempfile to diff against if we are creating a new file
  target_path = if ::File.exists?(@current_resource.path)
                  @current_resource.path
                else
                  suppress_resource_reporting = true  # suppress big diffs going to resource reporting service
                  tempfile = Tempfile.new('chef-tempfile')
                  tempfile.path
                end

  diff_filesize_threshold = Chef::Config[:diff_filesize_threshold]
  diff_output_threshold = Chef::Config[:diff_output_threshold]

  if ::File.size(target_path) > diff_filesize_threshold || ::File.size(temp_path) > diff_filesize_threshold
    return [ "(file sizes exceed #{diff_filesize_threshold} bytes, diff output suppressed)" ]
  end

  # MacOSX(BSD?) diff will *sometimes* happily spit out nasty binary diffs
  return [ "(current file is binary, diff output suppressed)"] if is_binary?(target_path)
  return [ "(new content is binary, diff output suppressed)"] if is_binary?(temp_path)

  begin
    # -u: Unified diff format
    result = shell_out("diff -u #{target_path} #{temp_path}" )
  rescue Exception => e
    # Should *not* receive this, but in some circumstances it seems that 
    # an exception can be thrown even using shell_out instead of shell_out!
    return [ "Could not determine diff. Error: #{e.message}" ]
  end

  # diff will set a non-zero return code even when there's 
  # valid stdout results, if it encounters something unexpected
  # So as long as we have output, we'll show it.
  if not result.stdout.empty?
    if result.stdout.length > diff_output_threshold
      [ "(long diff of over #{diff_output_threshold} characters, diff output suppressed)" ]
    else
      val = result.stdout.split("\n")
      val.delete("\\ No newline at end of file")
      @new_resource.diff(val.join("\\n")) unless suppress_resource_reporting
      val
    end
  elsif not result.stderr.empty?
    [ "Could not determine diff. Error: #{result.stderr}" ]
  else
    [ "(no diff)" ]
  end
end
diff_current_from_content(new_content) click to toggle source
# File lib/chef/provider/file.rb, line 49
def diff_current_from_content(new_content)
  result = nil
  Tempfile.open("chef-diff") do |file| 
    file.write new_content
    file.close 
    result = diff_current file.path
  end
  result
end
is_binary?(path) click to toggle source
# File lib/chef/provider/file.rb, line 59
def is_binary?(path)
  ::File.open(path) do |file|

    buff = file.read(Chef::Config[:diff_filesize_threshold])
    buff = "" if buff.nil?
    return buff !~ /^[\r[:print:]]*$/
  end
end
load_current_resource() click to toggle source
# File lib/chef/provider/file.rb, line 127
def load_current_resource
  # Every child should be specifying their own constructor, so this
  # should only be run in the file case.
  @current_resource ||= Chef::Resource::File.new(@new_resource.name)
  @new_resource.path.gsub!(/\\/, "/") # for Windows
  @current_resource.path(@new_resource.path)
  if !::File.directory?(@new_resource.path)
    if ::File.exist?(@new_resource.path)
      if @action != :create_if_missing  
        @current_resource.checksum(checksum(@new_resource.path))
      end
    end
  end
  load_current_resource_attrs
  setup_acl
  
  @current_resource
end
load_current_resource_attrs() click to toggle source
# File lib/chef/provider/file.rb, line 146
def load_current_resource_attrs
  if Chef::Platform.windows?
    # TODO: To work around CHEF-3554, add support for Windows
    # equivalent, or implicit resource reporting won't work for
    # Windows.
    return
  end

  if ::File.exist?(@new_resource.path)
    stat = ::File.stat(@new_resource.path)
    @current_resource.owner(stat.uid)
    @current_resource.mode(stat.mode & 07777)
    @current_resource.group(stat.gid)

    if @new_resource.group.nil?
      @new_resource.group(@current_resource.group)
    end 
    if @new_resource.owner.nil?
      @new_resource.owner(@current_resource.owner)
    end
    if @new_resource.mode.nil?
      @new_resource.mode(@current_resource.mode)
    end
  end
end
set_all_access_controls() click to toggle source
# File lib/chef/provider/file.rb, line 265
def set_all_access_controls
  if access_controls.requires_changes?
    converge_by(access_controls.describe_changes) do 
      access_controls.set_all
      #Update file state with new access values
      update_new_file_state
    end
  end
end
set_content() click to toggle source

Set the content of the file, assuming it is not set correctly already.

# File lib/chef/provider/file.rb, line 210
def set_content
  unless compare_content
    description = []
    description << "update content in file #{@new_resource.path} from #{short_cksum(@current_resource.checksum)} to #{short_cksum(new_resource_content_checksum)}"
    description << diff_current_from_content(@new_resource.content) 
    converge_by(description) do
      backup @new_resource.path if ::File.exists?(@new_resource.path)
      ::File.open(@new_resource.path, "w") {|f| f.write @new_resource.content }
      Chef::Log.info("#{@new_resource} contents updated")
    end
  end
end
setup_acl() click to toggle source
# File lib/chef/provider/file.rb, line 172
def setup_acl
  @acl_scanner = ScanAccessControl.new(@new_resource, @current_resource)
  @acl_scanner.set_all!
end
update_new_file_state(path=@new_resource.path) click to toggle source

if you are using a tempfile before creating, you must override the default with the tempfile, since the file at @new_resource.path will not be updated on converge

# File lib/chef/provider/file.rb, line 226
def update_new_file_state(path=@new_resource.path)
  if !::File.directory?(path) 
    @new_resource.checksum(checksum(path))
  end

  if Chef::Platform.windows?
    # TODO: To work around CHEF-3554, add support for Windows
    # equivalent, or implicit resource reporting won't work for
    # Windows.
    return
  end

  stat = ::File.stat(path)
  @new_resource.owner(stat.uid)
  @new_resource.mode(stat.mode & 07777)
  @new_resource.group(stat.gid)
end
whyrun_supported?() click to toggle source
# File lib/chef/provider/file.rb, line 123
def whyrun_supported?
  true
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.