File: dipper.rb

package info (click to toggle)
puppet-agent 7.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 19,092 kB
  • sloc: ruby: 245,074; sh: 456; makefile: 38; xml: 33
file content (174 lines) | stat: -rw-r--r-- 5,600 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
require 'pathname'
require_relative '../../puppet/file_bucket'
require_relative '../../puppet/file_bucket/file'
require_relative '../../puppet/indirector/request'
require_relative '../../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