From b4e5471383bb460d1ff4b88d6577594788e702dc Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Tue, 21 Jan 2020 10:33:44 -0800 Subject: more unified mode Signed-off-by: Lamont Granquist --- lib/chef/provider/apt_repository.rb | 358 ----------------------------------- lib/chef/resource/cron.rb | 1 + lib/chef/resource/cron_access.rb | 3 +- lib/chef/resource/cron_d.rb | 3 +- lib/chef/resource/csh.rb | 2 +- lib/chef/resource/directory.rb | 2 +- lib/chef/resource/dmg_package.rb | 6 +- lib/chef/resource/dnf_package.rb | 1 + lib/chef/resource/dpkg_package.rb | 4 +- lib/chef/resource/dsc_resource.rb | 2 +- lib/chef/resource/dsc_script.rb | 3 +- lib/chef/resource/freebsd_package.rb | 3 +- 12 files changed, 19 insertions(+), 369 deletions(-) delete mode 100644 lib/chef/provider/apt_repository.rb diff --git a/lib/chef/provider/apt_repository.rb b/lib/chef/provider/apt_repository.rb deleted file mode 100644 index 9443c58ef8..0000000000 --- a/lib/chef/provider/apt_repository.rb +++ /dev/null @@ -1,358 +0,0 @@ -# -# Author:: Thom May () -# Copyright:: Copyright (c) 2016-2018, 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_relative "../resource" -require_relative "../dsl/declare_resource" -require_relative "../mixin/shell_out" -require_relative "../http/simple" -require_relative "noop" -require "tmpdir" unless defined?(Dir.mktmpdir) - -class Chef - class Provider - class AptRepository < Chef::Provider - include Chef::Mixin::ShellOut - - provides :apt_repository, platform_family: "debian" - - LIST_APT_KEY_FINGERPRINTS = %w{apt-key adv --list-public-keys --with-fingerprint --with-colons}.freeze - - def load_current_resource; end - - action :add do - if new_resource.key.nil? - logger.debug "No 'key' property specified skipping key import" - else - new_resource.key.each do |k| - if is_key_id?(k) && !has_cookbook_file?(k) - install_key_from_keyserver(k) - else - install_key_from_uri(k) - end - end - end - - declare_resource(:execute, "apt-cache gencaches") do - command %w{apt-cache gencaches} - default_env true - ignore_failure true - action :nothing - end - - declare_resource(:apt_update, new_resource.name) do - ignore_failure true - action :nothing - end - - cleanup_legacy_file! - - repo = build_repo( - new_resource.uri, - new_resource.distribution, - repo_components, - new_resource.trusted, - new_resource.arch, - new_resource.deb_src - ) - - declare_resource(:file, "/etc/apt/sources.list.d/#{new_resource.repo_name}.list") do - owner "root" - group "root" - mode "0644" - content repo - sensitive new_resource.sensitive - action :create - notifies :run, "execute[apt-cache gencaches]", :immediately - notifies :update, "apt_update[#{new_resource.name}]", :immediately if new_resource.cache_rebuild - end - end - - action :remove do - cleanup_legacy_file! - if ::File.exist?("/etc/apt/sources.list.d/#{new_resource.repo_name}.list") - converge_by "Removing #{new_resource.repo_name} repository from /etc/apt/sources.list.d/" do - declare_resource(:file, "/etc/apt/sources.list.d/#{new_resource.repo_name}.list") do - sensitive new_resource.sensitive - action :delete - notifies :update, "apt_update[#{new_resource.name}]", :immediately if new_resource.cache_rebuild - end - - declare_resource(:apt_update, new_resource.name) do - ignore_failure true - action :nothing - end - end - else - logger.trace("/etc/apt/sources.list.d/#{new_resource.repo_name}.list does not exist. Nothing to do") - end - end - - # is the provided ID a key ID from a keyserver. Looks at length and HEX only values - # @param [String] id the key value passed by the user that *may* be an ID - def is_key_id?(id) - id = id[2..-1] if id.start_with?("0x") - id =~ /^\h+$/ && [8, 16, 40].include?(id.length) - end - - # run the specified command and extract the fingerprints from the output - # accepts a command so it can be used to extract both the current key's fingerprints - # and the fingerprint of the new key - # @param [Array] cmd the command to run - # - # @return [Array] an array of fingerprints - def extract_fingerprints_from_cmd(*cmd) - so = shell_out(*cmd) - so.stdout.split(/\n/).map do |t| - if z = t.match(/^fpr:+([0-9A-F]+):/) - z[1].split.join - end - end.compact - end - - # validate the key against the apt keystore to see if that version is expired - # @param [String] key - # - # @return [Boolean] is the key valid or not - def key_is_valid?(key) - valid = true - - so = shell_out("apt-key", "list") - so.stdout.split(/\n/).map do |t| - if t =~ %r{^\/#{key}.*\[expired: .*\]$} - logger.debug "Found expired key: #{t}" - valid = false - break - end - end - - logger.debug "key #{key} #{valid ? "is valid" : "is not valid"}" - valid - end - - # return the specified cookbook name or the cookbook containing the - # resource. - # - # @return [String] name of the cookbook - def cookbook_name - new_resource.cookbook || new_resource.cookbook_name - end - - # determine if a cookbook file is available in the run - # @param [String] fn the path to the cookbook file - # - # @return [Boolean] cookbook file exists or doesn't - def has_cookbook_file?(fn) - run_context.has_cookbook_file_in_cookbook?(cookbook_name, fn) - end - - # determine if there are any new keys by comparing the fingerprints of installed - # keys to those of the passed file - # @param [String] file the keyfile of the new repository - # - # @return [Boolean] true: no new keys in the file. false: there are new keys - def no_new_keys?(file) - # Now we are using the option --with-colons that works across old os versions - # as well as the latest (16.10). This for both `apt-key` and `gpg` commands - installed_keys = extract_fingerprints_from_cmd(*LIST_APT_KEY_FINGERPRINTS) - proposed_keys = extract_fingerprints_from_cmd("gpg", "--with-fingerprint", "--with-colons", file) - (installed_keys & proposed_keys).sort == proposed_keys.sort - end - - # Given the provided key URI determine what kind of chef resource we need - # to fetch the key - # @param [String] uri the uri of the gpg key (local path or http URL) - # - # @raise [Chef::Exceptions::FileNotFound] Key isn't remote or found in the current run - # - # @return [Symbol] :remote_file or :cookbook_file - def key_type(uri) - if uri.start_with?("http") - :remote_file - elsif has_cookbook_file?(uri) - :cookbook_file - else - raise Chef::Exceptions::FileNotFound, "Cannot locate key file: #{uri}" - end - end - - # Fetch the key using either cookbook_file or remote_file, validate it, - # and install it with apt-key add - # @param [String] key the key to install - # - # @raise [RuntimeError] Invalid key which can't verify the apt repository - # - # @return [void] - def install_key_from_uri(key) - key_name = key.gsub(/[^0-9A-Za-z\-]/, "_") - cached_keyfile = ::File.join(Chef::Config[:file_cache_path], key_name) - tmp_dir = Dir.mktmpdir(".gpg") - at_exit { FileUtils.remove_entry(tmp_dir) } - - declare_resource(key_type(key), cached_keyfile) do - source key - mode "0644" - sensitive new_resource.sensitive - action :create - verify "gpg --homedir #{tmp_dir} %{path}" - end - - declare_resource(:execute, "apt-key add #{cached_keyfile}") do - command [ "apt-key", "add", cached_keyfile ] - default_env true - sensitive new_resource.sensitive - action :run - not_if { no_new_keys?(cached_keyfile) } - notifies :run, "execute[apt-cache gencaches]", :immediately - end - end - - # build the apt-key command to install the keyserver - # @param [String] key the key to install - # @param [String] keyserver the key server to use - # - # @return [String] the full apt-key command to run - def keyserver_install_cmd(key, keyserver) - cmd = "apt-key adv --no-tty --recv" - cmd << " --keyserver-options http-proxy=#{new_resource.key_proxy}" if new_resource.key_proxy - cmd << " --keyserver " - cmd << if keyserver.start_with?("hkp://") - keyserver - else - "hkp://#{keyserver}:80" - end - - cmd << " #{key}" - cmd - end - - # @param [String] key - # @param [String] keyserver - # - # @raise [RuntimeError] Invalid key which can't verify the apt repository - # - # @return [void] - def install_key_from_keyserver(key, keyserver = new_resource.keyserver) - declare_resource(:execute, "install-key #{key}") do - command keyserver_install_cmd(key, keyserver) - default_env true - sensitive new_resource.sensitive - not_if do - present = extract_fingerprints_from_cmd(*LIST_APT_KEY_FINGERPRINTS).any? do |fp| - fp.end_with? key.upcase - end - present && key_is_valid?(key.upcase) - end - notifies :run, "execute[apt-cache gencaches]", :immediately - end - - raise "The key #{key} is invalid and cannot be used to verify an apt repository." unless key_is_valid?(key.upcase) - end - - # @param [String] owner - # @param [String] repo - # - # @raise [RuntimeError] Could not access the Launchpad PPA API - # - # @return [void] - def install_ppa_key(owner, repo) - url = "https://launchpad.net/api/1.0/~#{owner}/+archive/#{repo}" - key_id = Chef::HTTP::Simple.new(url).get("signing_key_fingerprint").delete('"') - install_key_from_keyserver(key_id, "keyserver.ubuntu.com") - rescue Net::HTTPClientException => e - raise "Could not access Launchpad ppa API: #{e.message}" - end - - # determine if the repository URL is a PPA - # @param [String] url the url of the repository - # - # @return [Boolean] is the repo URL a PPA - def is_ppa_url?(url) - url.start_with?("ppa:") - end - - # determine the repository's components: - # - "components" property if defined - # - "main" if "components" not defined and the repo is a PPA URL - # - otherwise nothing - # - # @return [String] the repository component - def repo_components - if is_ppa_url?(new_resource.uri) && new_resource.components.empty? - "main" - else - new_resource.components - end - end - - # given a PPA return a PPA URL in http://ppa.launchpad.net format - # @param [String] ppa the ppa URL - # - # @return [String] full PPA URL - def make_ppa_url(ppa) - owner, repo = ppa[4..-1].split("/") - repo ||= "ppa" - - install_ppa_key(owner, repo) - "http://ppa.launchpad.net/#{owner}/#{repo}/ubuntu" - end - - # build complete repo text that will be written to the config - # @param [String] uri - # @param [Array] components - # @param [Boolean] trusted - # @param [String] arch - # @param [Boolean] add_src - # - # @return [String] complete repo config text - def build_repo(uri, distribution, components, trusted, arch, add_src = false) - uri = make_ppa_url(uri) if is_ppa_url?(uri) - uri = URI.escape(uri) - components = Array(components).join(" ") - options = [] - options << "arch=#{arch}" if arch - options << "trusted=yes" if trusted - optstr = unless options.empty? - "[" + options.join(" ") + "]" - end - info = [ optstr, uri, distribution, components ].compact.join(" ") - repo = "deb #{info}\n" - repo << "deb-src #{info}\n" if add_src - repo - end - - # clean up a potentially legacy file from before we fixed the usage of - # new_resource.name vs. new_resource.repo_name. We might have the - # name.list file hanging around and need to clean it up. - # - # @return [void] - def cleanup_legacy_file! - legacy_path = "/etc/apt/sources.list.d/#{new_resource.name}.list" - if new_resource.name != new_resource.repo_name && ::File.exist?(legacy_path) - converge_by "Cleaning up legacy #{legacy_path} repo file" do - declare_resource(:file, legacy_path) do - action :delete - # Not triggering an update since it isn't super likely to be needed. - end - end - end - end - end - end -end - -Chef::Provider::Noop.provides :apt_repository diff --git a/lib/chef/resource/cron.rb b/lib/chef/resource/cron.rb index 6f85d68e5d..0f39347e0f 100644 --- a/lib/chef/resource/cron.rb +++ b/lib/chef/resource/cron.rb @@ -23,6 +23,7 @@ require_relative "../provider/cron" # do not remove. we actually need this below class Chef class Resource class Cron < Chef::Resource + unified_mode true resource_name :cron provides :cron diff --git a/lib/chef/resource/cron_access.rb b/lib/chef/resource/cron_access.rb index 3ee371e9fa..1d5b2dc358 100644 --- a/lib/chef/resource/cron_access.rb +++ b/lib/chef/resource/cron_access.rb @@ -3,7 +3,7 @@ # Author:: Tim Smith # # Copyright:: 2014-2018, Sander Botman -# Copyright:: 2018-2019, Chef Software, Inc. +# Copyright:: 2018-2019, Chef Software Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ require_relative "../resource" class Chef class Resource class CronAccess < Chef::Resource + unified_mode true resource_name :cron_access provides(:cron_manage) # legacy name @todo in Chef 15 we should { true } this so it wins over the cookbook diff --git a/lib/chef/resource/cron_d.rb b/lib/chef/resource/cron_d.rb index 281fad9dae..420e19d707 100644 --- a/lib/chef/resource/cron_d.rb +++ b/lib/chef/resource/cron_d.rb @@ -1,5 +1,5 @@ # -# Copyright:: 2008-2019, Chef Software, Inc. +# Copyright:: 2008-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ require_relative "../dist" class Chef class Resource class CronD < Chef::Resource + unified_mode true resource_name :cron_d introduced "14.4" diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb index ea8e44c175..b04f7f9cee 100644 --- a/lib/chef/resource/csh.rb +++ b/lib/chef/resource/csh.rb @@ -1,6 +1,6 @@ # # Author:: Adam Jacob () -# Copyright:: Copyright 2008-2016, Chef Software Inc. +# Copyright:: Copyright 2008-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb index b817a3ff08..f072584121 100644 --- a/lib/chef/resource/directory.rb +++ b/lib/chef/resource/directory.rb @@ -2,7 +2,7 @@ # Author:: Adam Jacob () # Author:: Seth Chisamore () # Author:: Tyler Cloke () -# Copyright:: Copyright 2008-2017, Chef Software Inc. +# Copyright:: Copyright 2008-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/chef/resource/dmg_package.rb b/lib/chef/resource/dmg_package.rb index cb115a235f..07ab920411 100644 --- a/lib/chef/resource/dmg_package.rb +++ b/lib/chef/resource/dmg_package.rb @@ -20,6 +20,7 @@ require_relative "../resource" class Chef class Resource class DmgPackage < Chef::Resource + unified_mode true resource_name :dmg_package provides(:dmg_package) { true } @@ -129,8 +130,8 @@ class Chef end end - ruby_block "attach #{dmg_file}" do - block do + unless dmg_attached? + converge_by "attach #{dmg_file}" do raise "This DMG package requires EULA acceptance. Add 'accept_eula true' to dmg_package resource to accept the EULA during installation." if software_license_agreement? && !new_resource.accept_eula attach_cmd = new_resource.accept_eula ? "yes | " : "" @@ -138,7 +139,6 @@ class Chef shell_out!(attach_cmd, env: { "PAGER" => "true" }) end - not_if { dmg_attached? } end case new_resource.type diff --git a/lib/chef/resource/dnf_package.rb b/lib/chef/resource/dnf_package.rb index b4eabbc3c7..6d0810ab2a 100644 --- a/lib/chef/resource/dnf_package.rb +++ b/lib/chef/resource/dnf_package.rb @@ -26,6 +26,7 @@ class Chef extend Chef::Mixin::Which extend Chef::Mixin::ShellOut + unified_mode true resource_name :dnf_package # all rhel variants >= 8 will use DNF diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb index 116e17d6a6..7ce4da6b85 100644 --- a/lib/chef/resource/dpkg_package.rb +++ b/lib/chef/resource/dpkg_package.rb @@ -1,6 +1,6 @@ # # Author:: Adam Jacob () -# Copyright:: Copyright 2008-2016, Chef Software, Inc. +# Copyright:: Copyright 2008-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,8 @@ require_relative "package" class Chef class Resource class DpkgPackage < Chef::Resource::Package + unified_mode true + resource_name :dpkg_package provides :dpkg_package diff --git a/lib/chef/resource/dsc_resource.rb b/lib/chef/resource/dsc_resource.rb index fe47d7fd1a..9c17139544 100644 --- a/lib/chef/resource/dsc_resource.rb +++ b/lib/chef/resource/dsc_resource.rb @@ -1,7 +1,7 @@ # # Author:: Adam Edwards () # -# Copyright:: Copyright 2014-2016, Chef Software Inc. +# Copyright:: Copyright 2014-2019, Chef Software Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb index 2ebb224b5b..34662ff3b9 100644 --- a/lib/chef/resource/dsc_script.rb +++ b/lib/chef/resource/dsc_script.rb @@ -1,6 +1,6 @@ # # Author:: Adam Edwards () -# Copyright:: Copyright 2014-2016, Chef Software, Inc. +# Copyright:: Copyright 2014-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ class Chef class DscScript < Chef::Resource include Chef::DSL::Powershell + unified_mode true resource_name :dsc_script provides :dsc_script diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb index dccb1e1a4f..bc94190c5b 100644 --- a/lib/chef/resource/freebsd_package.rb +++ b/lib/chef/resource/freebsd_package.rb @@ -1,7 +1,7 @@ # # Authors:: AJ Christensen () # Richard Manyanza () -# Copyright:: Copyright 2008-2016, Chef Software Inc. +# Copyright:: Copyright 2008-2019, Chef Software Inc. # Copyright:: Copyright 2014-2016, Richard Manyanza. # License:: Apache License, Version 2.0 # @@ -28,6 +28,7 @@ class Chef class FreebsdPackage < Chef::Resource::Package include Chef::Mixin::ShellOut + unified_mode true resource_name :freebsd_package provides :package, platform: "freebsd" -- cgit v1.2.1