diff options
-rw-r--r-- | lib/chef/deprecation/mixin/template.rb | 48 | ||||
-rw-r--r-- | lib/chef/deprecation/provider/cookbook_file.rb | 54 | ||||
-rw-r--r-- | lib/chef/deprecation/provider/file.rb | 198 | ||||
-rw-r--r-- | lib/chef/deprecation/provider/remote_directory.rb | 52 | ||||
-rw-r--r-- | lib/chef/deprecation/provider/remote_file.rb | 85 | ||||
-rw-r--r-- | lib/chef/deprecation/provider/template.rb | 63 | ||||
-rw-r--r-- | lib/chef/provider/cookbook_file.rb | 6 | ||||
-rw-r--r-- | lib/chef/provider/file.rb | 6 | ||||
-rw-r--r-- | lib/chef/provider/remote_directory.rb | 12 | ||||
-rw-r--r-- | lib/chef/provider/remote_file.rb | 6 | ||||
-rw-r--r-- | lib/chef/provider/template.rb | 6 | ||||
-rw-r--r-- | spec/unit/deprecation_spec.rb | 14 |
12 files changed, 550 insertions, 0 deletions
diff --git a/lib/chef/deprecation/mixin/template.rb b/lib/chef/deprecation/mixin/template.rb new file mode 100644 index 0000000000..0c902123cf --- /dev/null +++ b/lib/chef/deprecation/mixin/template.rb @@ -0,0 +1,48 @@ +# +# Author:: Serdar Sutay (<serdar@chef.io>) +# Copyright:: Copyright 2013-2016, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "tempfile" +require "erubis" + +class Chef + module Deprecation + module Mixin + # == Deprecation::Provider::Mixin::Template + # This module contains the deprecated functions of + # Chef::Mixin::Template. These functions are refactored to different + # components. They are frozen and will be removed in Chef 13. + # + + module Template + def render_template(template, context) + begin + eruby = Erubis::Eruby.new(template) + output = eruby.evaluate(context) + rescue Object => e + raise TemplateError.new(e, template, context) + end + Tempfile.open("chef-rendered-template") do |tempfile| + tempfile.print(output) + tempfile.close + yield tempfile + end + end + end + end + end +end diff --git a/lib/chef/deprecation/provider/cookbook_file.rb b/lib/chef/deprecation/provider/cookbook_file.rb new file mode 100644 index 0000000000..d6e8a7566e --- /dev/null +++ b/lib/chef/deprecation/provider/cookbook_file.rb @@ -0,0 +1,54 @@ +# +# Author:: Serdar Sutay (<serdar@chef.io>) +# Copyright:: Copyright 2013-2016, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + module Deprecation + module Provider + + # == Deprecation::Provider::CookbookFile + # This module contains the deprecated functions of + # Chef::Provider::CookbookFile. These functions are refactored to + # different components. They are frozen and will be removed in Chef 13. + # + module CookbookFile + + def file_cache_location + @file_cache_location ||= begin + cookbook = run_context.cookbook_collection[resource_cookbook] + cookbook.preferred_filename_on_disk_location(node, :files, @new_resource.source, @new_resource.path) + end + end + + def resource_cookbook + @new_resource.cookbook || @new_resource.cookbook_name + end + + def content_stale? + ( ! ::File.exist?(@new_resource.path)) || ( ! compare_content) + end + + def backup_new_resource + if ::File.exists?(@new_resource.path) + backup @new_resource.path + end + end + + end + end + end +end diff --git a/lib/chef/deprecation/provider/file.rb b/lib/chef/deprecation/provider/file.rb new file mode 100644 index 0000000000..edb0052fdf --- /dev/null +++ b/lib/chef/deprecation/provider/file.rb @@ -0,0 +1,198 @@ +# +# Author:: Serdar Sutay (<serdar@chef.io>) +# Copyright:: Copyright 2013-2016, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "chef/util/path_helper" + +class Chef + module Deprecation + module Provider + + # == Deprecation::Provider::File + # This module contains the deprecated functions of + # Chef::Provider::File. These functions are refactored to different + # components. They are frozen and will be removed in Chef 13. + # + module File + + 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 + + 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 + + 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 + + def setup_acl + return if Chef::Platform.windows? + acl_scanner = ScanAccessControl.new(@new_resource, @current_resource) + acl_scanner.set_all! + end + + def compare_content + checksum(@current_resource.path) == new_resource_content_checksum + end + + 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 + + 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 + + acl_scanner = ScanAccessControl.new(@new_resource, @new_resource) + acl_scanner.set_all! + end + + 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 + + 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 + + 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[Chef::Util::PathHelper.escape_glob_dir(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 + + end + end + end +end diff --git a/lib/chef/deprecation/provider/remote_directory.rb b/lib/chef/deprecation/provider/remote_directory.rb new file mode 100644 index 0000000000..9b442651d7 --- /dev/null +++ b/lib/chef/deprecation/provider/remote_directory.rb @@ -0,0 +1,52 @@ +# +# Author:: Serdar Sutay (<serdar@chef.io>) +# Copyright:: Copyright 2013-2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + module Deprecation + module Provider + module RemoteDirectory + + def directory_root_in_cookbook_cache + Chef.deprecated :internal_api, "the Chef::Provider::RemoteDirectory#directory_root_in_cookbook_cache method is deprecated" + + @directory_root_in_cookbook_cache ||= + begin + cookbook = run_context.cookbook_collection[resource_cookbook] + cookbook.preferred_filename_on_disk_location(node, :files, source, path) + end + end + + # List all excluding . and .. + def ls(path) + files = Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob_dir(path), "**", "*"), + ::File::FNM_DOTMATCH) + + # Remove current directory and previous directory + files = files.reject do |name| + basename = Pathname.new(name).basename().to_s + [".", ".."].include?(basename) + end + + # Clean all the paths... this is required because of the join + files.map { |f| Chef::Util::PathHelper.cleanpath(f) } + end + + end + end + end +end diff --git a/lib/chef/deprecation/provider/remote_file.rb b/lib/chef/deprecation/provider/remote_file.rb new file mode 100644 index 0000000000..aefb04752e --- /dev/null +++ b/lib/chef/deprecation/provider/remote_file.rb @@ -0,0 +1,85 @@ +# +# Author:: Serdar Sutay (<serdar@chef.io>) +# Copyright:: Copyright 2013-2016, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + module Deprecation + module Provider + + # == Deprecation::Provider::RemoteFile + # This module contains the deprecated functions of + # Chef::Provider::RemoteFile. These functions are refactored to different + # components. They are frozen and will be removed in Chef 13. + # + module RemoteFile + + def current_resource_matches_target_checksum? + @new_resource.checksum && @current_resource.checksum && @current_resource.checksum =~ /^#{Regexp.escape(@new_resource.checksum)}/ + end + + def matches_current_checksum?(candidate_file) + Chef::Log.debug "#{@new_resource} checking for file existence of #{@new_resource.path}" + if ::File.exists?(@new_resource.path) + Chef::Log.debug "#{@new_resource} file exists at #{@new_resource.path}" + @new_resource.checksum(checksum(candidate_file.path)) + Chef::Log.debug "#{@new_resource} target checksum: #{@current_resource.checksum}" + Chef::Log.debug "#{@new_resource} source checksum: #{@new_resource.checksum}" + + @new_resource.checksum == @current_resource.checksum + else + Chef::Log.debug "#{@new_resource} creating #{@new_resource.path}" + false + end + end + + def backup_new_resource + if ::File.exists?(@new_resource.path) + Chef::Log.debug "#{@new_resource} checksum changed from #{@current_resource.checksum} to #{@new_resource.checksum}" + backup @new_resource.path + end + end + + def source_file(source, current_checksum, &block) + if absolute_uri?(source) + fetch_from_uri(source, &block) + elsif !Chef::Config[:solo_legacy_mode] + fetch_from_chef_server(source, current_checksum, &block) + else + fetch_from_local_cookbook(source, &block) + end + end + + def http_client_opts(source) + opts = {} + # CHEF-3140 + # 1. If it's already compressed, trying to compress it more will + # probably be counter-productive. + # 2. Some servers are misconfigured so that you GET $URL/file.tgz but + # they respond with content type of tar and content encoding of gzip, + # which tricks Chef::REST into decompressing the response body. In this + # case you'd end up with a tar archive (no gzip) named, e.g., foo.tgz, + # which is not what you wanted. + if @new_resource.path =~ /gz$/ || source =~ /gz$/ + opts[:disable_gzip] = true + end + opts + end + + end + end + end +end diff --git a/lib/chef/deprecation/provider/template.rb b/lib/chef/deprecation/provider/template.rb new file mode 100644 index 0000000000..ea5a880798 --- /dev/null +++ b/lib/chef/deprecation/provider/template.rb @@ -0,0 +1,63 @@ +# +# Author:: Serdar Sutay (<serdar@chef.io>) +# Copyright:: Copyright 2013-2016, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "chef/deprecation/mixin/template" + +class Chef + module Deprecation + module Provider + + # == Deprecation::Provider::Template + # This module contains the deprecated functions of + # Chef::Provider::Template. These functions are refactored to different + # components. They are frozen and will be removed in Chef 13. + # + module Template + + include Chef::Deprecation::Mixin::Template + + def template_finder + @template_finder ||= begin + Chef::Provider::TemplateFinder.new(run_context, cookbook_name, node) + end + end + + def template_location + @template_file_cache_location ||= begin + template_finder.find(@new_resource.source, :local => @new_resource.local, :cookbook => @new_resource.cookbook) + end + end + + def resource_cookbook + @new_resource.cookbook || @new_resource.cookbook_name + end + + def rendered(rendered_template) + @new_resource.checksum(checksum(rendered_template.path)) + Chef::Log.debug("Current content's checksum: #{@current_resource.checksum}") + Chef::Log.debug("Rendered content's checksum: #{@new_resource.checksum}") + end + + def content_matches? + @current_resource.checksum == @new_resource.checksum + end + + end + end + end +end diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb index 92383fd5fa..dc900d871b 100644 --- a/lib/chef/provider/cookbook_file.rb +++ b/lib/chef/provider/cookbook_file.rb @@ -17,6 +17,8 @@ # require "chef/provider/file" +require "chef/deprecation/provider/cookbook_file" +require "chef/deprecation/warnings" class Chef class Provider @@ -24,6 +26,10 @@ class Chef provides :cookbook_file + extend Chef::Deprecation::Warnings + include Chef::Deprecation::Provider::CookbookFile + add_deprecation_warnings_for(Chef::Deprecation::Provider::CookbookFile.instance_methods) + def initialize(new_resource, run_context) @content_class = Chef::Provider::CookbookFile::Content super diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb index 2bf3561853..ecde068751 100644 --- a/lib/chef/provider/file.rb +++ b/lib/chef/provider/file.rb @@ -30,6 +30,8 @@ require "chef/mixin/enforce_ownership_and_permissions" require "chef/util/backup" require "chef/util/diff" require "chef/util/selinux" +require "chef/deprecation/provider/file" +require "chef/deprecation/warnings" require "chef/file_content_management/deploy" # The Tao of File Providers: @@ -50,6 +52,10 @@ class Chef include Chef::Util::Selinux include Chef::Mixin::FileClass + extend Chef::Deprecation::Warnings + include Chef::Deprecation::Provider::File + add_deprecation_warnings_for(Chef::Deprecation::Provider::File.instance_methods) + provides :file attr_reader :deployment_strategy diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb index 6f4956de96..d2f90d233b 100644 --- a/lib/chef/provider/remote_directory.rb +++ b/lib/chef/provider/remote_directory.rb @@ -23,6 +23,8 @@ require "chef/resource/cookbook_file" require "chef/mixin/file_class" require "chef/platform/query_helpers" require "chef/util/path_helper" +require "chef/deprecation/warnings" +require "chef/deprecation/provider/remote_directory" require "forwardable" @@ -266,6 +268,16 @@ class Chef res end + # + # Add back deprecated methods and aliases that are internally unused and should be removed in Chef-13 + # + extend Chef::Deprecation::Warnings + include Chef::Deprecation::Provider::RemoteDirectory + add_deprecation_warnings_for(Chef::Deprecation::Provider::RemoteDirectory.instance_methods) + + alias_method :resource_for_directory, :directory_resource + add_deprecation_warnings_for([:resource_for_directory]) + end end end diff --git a/lib/chef/provider/remote_file.rb b/lib/chef/provider/remote_file.rb index c0a0f9433c..05e213e842 100644 --- a/lib/chef/provider/remote_file.rb +++ b/lib/chef/provider/remote_file.rb @@ -18,12 +18,18 @@ # require "chef/provider/file" +require "chef/deprecation/provider/remote_file" +require "chef/deprecation/warnings" class Chef class Provider class RemoteFile < Chef::Provider::File provides :remote_file + extend Chef::Deprecation::Warnings + include Chef::Deprecation::Provider::RemoteFile + add_deprecation_warnings_for(Chef::Deprecation::Provider::RemoteFile.instance_methods) + def initialize(new_resource, run_context) @content_class = Chef::Provider::RemoteFile::Content super diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb index 05cdbdbf62..7cb0ba008d 100644 --- a/lib/chef/provider/template.rb +++ b/lib/chef/provider/template.rb @@ -19,12 +19,18 @@ require "chef/provider/template_finder" require "chef/provider/file" +require "chef/deprecation/provider/template" +require "chef/deprecation/warnings" class Chef class Provider class Template < Chef::Provider::File provides :template + extend Chef::Deprecation::Warnings + include Chef::Deprecation::Provider::Template + add_deprecation_warnings_for(Chef::Deprecation::Provider::Template.instance_methods) + def initialize(new_resource, run_context) @content_class = Chef::Provider::Template::Content super diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb index 6e2bcc32fd..41c1724e5b 100644 --- a/spec/unit/deprecation_spec.rb +++ b/spec/unit/deprecation_spec.rb @@ -45,6 +45,20 @@ describe Chef::Deprecation do add_deprecation_warnings_for(DeprecatedMethods.instance_methods) end + method_snapshot_file = File.join(CHEF_SPEC_DATA, "file-providers-method-snapshot-chef-11-4.json") + method_snapshot = Chef::JSONCompat.parse(File.open(method_snapshot_file).read()) + + method_snapshot.each do |class_name, old_methods| + class_object = class_from_string(class_name) + current_methods = class_object.public_instance_methods.map(&:to_sym) + + it "defines all methods on #{class_object} that were available in 11.0" do + old_methods.each do |old_method| + expect(current_methods).to include(old_method.to_sym) + end + end + end + context "when Chef::Config[:treat_deprecation_warnings_as_errors] is off" do before do Chef::Config[:treat_deprecation_warnings_as_errors] = false |