require 'pathname'
require 'puppet/file_bucket'
require 'puppet/file_bucket/file'
require 'puppet/indirector/request'
require 'puppet/util/diff'
require 'tempfile'
class Puppet::FileBucket::Dipper
include Puppet::Util::Checksums
# This is a transitional implementation that uses REST
# to access remote filebucket files.
attr_accessor :name
# Creates a bucket client
def initialize(hash = {})
# Emulate the XMLRPC client
server = hash[:Server]
port = hash[:Port] || Puppet[:serverport]
if hash.include?(:Path)
@local_path = hash[:Path]
@rest_path = nil
else
@local_path = nil
@rest_path = "filebucket://#{server}:#{port}/"
end
@checksum_type = Puppet[:digest_algorithm].to_sym
@digest = method(@checksum_type)
end
def local?
!! @local_path
end
# Backs up a file to the file bucket
def backup(file)
file_handle = Puppet::FileSystem.pathname(file)
raise(ArgumentError, _("File %{file} does not exist") % { file: file }) unless Puppet::FileSystem.exist?(file_handle)
begin
file_bucket_file = Puppet::FileBucket::File.new(file_handle, :bucket_path => @local_path)
files_original_path = absolutize_path(file)
dest_path = "#{@rest_path}#{file_bucket_file.name}/#{files_original_path}"
file_bucket_path = "#{@rest_path}#{file_bucket_file.checksum_type}/#{file_bucket_file.checksum_data}/#{files_original_path}"
# Make a HEAD request for the file so that we don't waste time
# uploading it if it already exists in the bucket.
unless Puppet::FileBucket::File.indirection.head(file_bucket_path, :bucket_path => file_bucket_file.bucket_path)
Puppet::FileBucket::File.indirection.save(file_bucket_file, dest_path)
end
return file_bucket_file.checksum_data
rescue => detail
message = _("Could not back up %{file}: %{detail}") % { file: file, detail: detail }
Puppet.log_exception(detail, message)
raise Puppet::Error, message, detail.backtrace
end
end
# Diffs two filebucket files identified by their sums
def diff(checksum_a, checksum_b, file_a, file_b)
raise RuntimeError, _("Diff is not supported on this platform") if Puppet[:diff] == ""
if checksum_a
source_path = "#{@rest_path}#{@checksum_type}/#{checksum_a}"
if checksum_b
file_diff = Puppet::FileBucket::File.indirection.find(
source_path,
:bucket_path => @local_path,
:diff_with => checksum_b)
elsif file_b
tmp_file = ::Tempfile.new('diff')
begin
restore(tmp_file.path, checksum_a)
file_diff = Puppet::Util::Diff.diff(tmp_file.path, file_b)
ensure
tmp_file.close
tmp_file.unlink
end
else
raise Puppet::Error, _("Please provide a file or checksum to diff with")
end
elsif file_a
if checksum_b
tmp_file = ::Tempfile.new('diff')
begin
restore(tmp_file.path, checksum_b)
file_diff = Puppet::Util::Diff.diff(file_a, tmp_file.path)
ensure
tmp_file.close
tmp_file.unlink
end
elsif file_b
file_diff = Puppet::Util::Diff.diff(file_a, file_b)
end
end
raise Puppet::Error, _("Failed to diff files") unless file_diff
file_diff.to_s
end
# Retrieves a file by sum.
def getfile(sum)
get_bucket_file(sum).to_s
end
# Retrieves a FileBucket::File by sum.
def get_bucket_file(sum)
source_path = "#{@rest_path}#{@checksum_type}/#{sum}"
file_bucket_file = Puppet::FileBucket::File.indirection.find(source_path, :bucket_path => @local_path)
raise Puppet::Error, _("File not found") unless file_bucket_file
file_bucket_file
end
# Restores the file
def restore(file, sum)
restore = true
file_handle = Puppet::FileSystem.pathname(file)
if Puppet::FileSystem.exist?(file_handle)
cursum = Puppet::FileBucket::File.new(file_handle).checksum_data()
# if the checksum has changed...
# this might be extra effort
if cursum == sum
restore = false
end
end
if restore
newcontents = get_bucket_file(sum)
if newcontents
newsum = newcontents.checksum_data
changed = nil
if Puppet::FileSystem.exist?(file_handle) and ! Puppet::FileSystem.writable?(file_handle)
changed = Puppet::FileSystem.stat(file_handle).mode
::File.chmod(changed | 0200, file)
end
::File.open(file, ::File::WRONLY|::File::TRUNC|::File::CREAT) { |of|
of.binmode
newcontents.stream do |source_stream|
FileUtils.copy_stream(source_stream, of)
end
}
::File.chmod(changed, file) if changed
else
Puppet.err _("Could not find file with checksum %{sum}") % { sum: sum }
return nil
end
return newsum
else
return nil
end
end
# List Filebucket content.
def list(fromdate, todate)
raise Puppet::Error, _("Listing remote file buckets is not allowed") unless local?
source_path = "#{@rest_path}#{@checksum_type}/"
file_bucket_list = Puppet::FileBucket::File.indirection.find(
source_path,
:bucket_path => @local_path,
:list_all => true,
:fromdate => fromdate,
:todate => todate)
raise Puppet::Error, _("File not found") unless file_bucket_list
file_bucket_list.to_s
end
private
def absolutize_path( path )
Pathname.new(path).realpath
end
end
Copyright 2K16 - 2K18 Indonesian Hacker Rulez