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
|
require 'puppet/indirector/code'
require 'puppet/file_bucket/file'
require 'puppet/util/checksums'
require 'fileutils'
module Puppet::FileBucketFile
class File < Puppet::Indirector::Code
include Puppet::Util::Checksums
desc "Store files in a directory set based on their checksums."
def initialize
Puppet.settings.use(:filebucket)
end
def find( request )
checksum, path = request_to_checksum_and_path( request )
return find_by_checksum( checksum, request.options )
end
def save( request )
checksum, path = request_to_checksum_and_path( request )
instance = request.instance
instance.checksum = checksum if checksum
instance.path = path if path
save_to_disk(instance)
instance.to_s
end
private
def find_by_checksum( checksum, options )
model.new( nil, :checksum => checksum ) do |bucket_file|
bucket_file.bucket_path = options[:bucket_path]
filename = contents_path_for( bucket_file )
if ! ::File.exist? filename
return nil
end
begin
contents = ::File.read filename
Puppet.info "FileBucket read #{bucket_file.checksum}"
rescue RuntimeError => e
raise Puppet::Error, "file could not be read: #{e.message}"
end
if ::File.exist?(paths_path_for( bucket_file) )
::File.open(paths_path_for( bucket_file) ) do |f|
bucket_file.paths = f.readlines.map { |l| l.chomp }
end
end
bucket_file.contents = contents
end
end
def save_to_disk( bucket_file )
# If the file already exists, just return the md5 sum.
if ::File.exist?(contents_path_for( bucket_file) )
verify_identical_file!(bucket_file)
else
# Make the directories if necessary.
unless ::File.directory?( path_for( bucket_file) )
Puppet::Util.withumask(0007) do
::FileUtils.mkdir_p( path_for( bucket_file) )
end
end
Puppet.info "FileBucket adding #{bucket_file.path} as #{bucket_file.checksum}"
# Write the file to disk.
Puppet::Util.withumask(0007) do
::File.open(contents_path_for(bucket_file), ::File::WRONLY|::File::CREAT, 0440) do |of|
of.print bucket_file.contents
end
end
end
save_path_to_paths_file(bucket_file)
return bucket_file.checksum_data
end
def request_to_checksum_and_path( request )
return [request.key, nil] if checksum?(request.key)
checksum_type, checksum, path = request.key.split(/\//, 3)
return nil if checksum_type.to_s == ""
return [ "{#{checksum_type}}#{checksum}", path ]
end
def path_for(bucket_file, subfile = nil)
bucket_path = bucket_file.bucket_path || Puppet[:bucketdir]
digest = bucket_file.checksum_data
dir = ::File.join(digest[0..7].split(""))
basedir = ::File.join(bucket_path, dir, digest)
return basedir unless subfile
return ::File.join(basedir, subfile)
end
def contents_path_for(bucket_file)
path_for(bucket_file, "contents")
end
def paths_path_for(bucket_file)
path_for(bucket_file, "paths")
end
def content_check?
true
end
# If conflict_check is enabled, verify that the passed text is
# the same as the text in our file.
def verify_identical_file!(bucket_file)
return unless content_check?
disk_contents = ::File.read(contents_path_for(bucket_file))
# If the contents don't match, then we've found a conflict.
# Unlikely, but quite bad.
if disk_contents != bucket_file.contents
raise Puppet::FileBucket::BucketError, "Got passed new contents for sum #{bucket_file.checksum}", caller
else
Puppet.info "FileBucket got a duplicate file #{bucket_file.path} (#{bucket_file.checksum})"
end
end
def save_path_to_paths_file(bucket_file)
return unless bucket_file.path
# check for dupes
if ::File.exist?(paths_path_for( bucket_file) )
::File.open(paths_path_for( bucket_file) ) do |f|
return if f.readlines.collect { |l| l.chomp }.include?(bucket_file.path)
end
end
# if it's a new file, or if our path isn't in the file yet, add it
::File.open(paths_path_for(bucket_file), ::File::WRONLY|::File::CREAT|::File::APPEND) do |of|
of.puts bucket_file.path
end
end
end
end
|