Class: Chef::Provider::File
Constant Summary
Mixin::ShellOut::DEPRECATED_OPTIONS
Instance Attribute Summary
#action, #current_resource, #new_resource, #run_context
Instance Method Summary
collapse
#run_command_compatible_options, #shell_out, #shell_out!
#checksum
#access_controls, #enforce_ownership_and_permissions
#action_nothing, #cleanup_after_converge, #cookbook_name, #events, #initialize, #node, #process_resource_requirements, #requirements, #resource_collection, #run_action, #set_updated_status, #whyrun_mode?
#method_missing
#convert_to_class_name, #convert_to_snake_case, #filename_to_qualified_string, #snake_case_basename
Constructor Details
This class inherits a constructor from Chef::Provider
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
in the class Chef::DSL::Recipe
Instance Method Details
#action_create ⇒ Object
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
# File 'lib/chef/provider/file.rb', line 217
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 ⇒ Object
248
249
250
251
252
253
254
|
# File 'lib/chef/provider/file.rb', line 248
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 ⇒ Object
256
257
258
259
260
261
262
263
264
|
# File 'lib/chef/provider/file.rb', line 256
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 ⇒ Object
266
267
268
269
270
271
272
273
|
# File 'lib/chef/provider/file.rb', line 266
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) ⇒ Object
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
# File 'lib/chef/provider/file.rb', line 275
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]:)/, "") 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}")
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 ⇒ Object
Compare the content of a file. Returns true if they are the same, false if they are not.
180
181
182
|
# File 'lib/chef/provider/file.rb', line 180
def compare_content
checksum(@current_resource.path) == new_resource_content_checksum
end
|
#define_resource_requirements ⇒ Object
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
# File 'lib/chef/provider/file.rb', line 152
def define_resource_requirements
access_controls.requires_changes?
requirements.assert(:create, :create_if_missing, :touch) do |a|
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
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 ⇒ Object
304
305
306
307
308
309
310
311
312
313
314
|
# File 'lib/chef/provider/file.rb', line 304
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) ⇒ Object
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
|
# File 'lib/chef/provider/file.rb', line 70
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)
target_path = if ::File.exists?(@current_resource.path)
@current_resource.path
else
suppress_resource_reporting = true 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
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
result = shell_out("diff -u #{target_path} #{temp_path}" )
rescue Exception => e
return [ "Could not determine diff. Error: #{e.message}" ]
end
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) ⇒ Object
50
51
52
53
54
55
56
57
58
|
# File 'lib/chef/provider/file.rb', line 50
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) ⇒ Boolean
60
61
62
63
64
65
66
67
|
# File 'lib/chef/provider/file.rb', line 60
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 ⇒ Object
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
# File 'lib/chef/provider/file.rb', line 128
def load_current_resource
@current_resource ||= Chef::Resource::File.new(@new_resource.name)
@new_resource.path.gsub!(/\\/, "/") @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
setup_acl
@current_resource
end
|
#set_all_access_controls ⇒ Object
238
239
240
241
242
243
244
245
246
|
# File 'lib/chef/provider/file.rb', line 238
def set_all_access_controls
if access_controls.requires_changes?
converge_by(access_controls.describe_changes) do
access_controls.set_all
update_new_file_state
end
end
end
|
#set_content ⇒ Object
Set the content of the file, assuming it is not set correctly already.
185
186
187
188
189
190
191
192
193
194
195
196
|
# File 'lib/chef/provider/file.rb', line 185
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
|
#update_new_file_state(path = @new_resource.path) ⇒ Object
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
# File 'lib/chef/provider/file.rb', line 201
def update_new_file_state(path=@new_resource.path)
if !::File.directory?(path)
@new_resource.checksum(checksum(path))
end
if Chef::Platform.windows?
return
end
acl_scanner = ScanAccessControl.new(@new_resource, @new_resource)
acl_scanner.set_all!
end
|
#whyrun_supported? ⇒ Boolean
124
125
126
|
# File 'lib/chef/provider/file.rb', line 124
def whyrun_supported?
true
end
|