diff options
72 files changed, 1919 insertions, 220 deletions
diff --git a/.gitignore b/.gitignore index 35aecf92cc..2e2447ae2c 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,6 @@ kitchen-tests/vendor # Visual Studio Code files .vscode + +# ignore nodes generated during local testing +nodes/ diff --git a/.travis.yml b/.travis.yml index db5edab1ad..7f3a518d53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,18 +61,18 @@ matrix: - env: UNIT_SPECS_24: 1 rvm: 2.4.3 - sudo: true + sudo: false script: - - sudo -E $(which bundle) exec rake spec:unit; - - sudo -E $(which bundle) exec rake component_specs + - bundle exec rake spec:unit; + - bundle exec rake component_specs bundler_args: --without ci docgen guard integration maintenance omnibus_package --frozen - env: UNIT_SPECS_25: 1 rvm: 2.5.0 - sudo: true + sudo: false script: - - sudo -E $(which bundle) exec rake spec:unit; - - sudo -E $(which bundle) exec rake component_specs + - bundle exec rake spec:unit; + - bundle exec rake component_specs bundler_args: --without ci docgen guard integration maintenance omnibus_package --frozen - env: CHEFSTYLE: 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index b6c23086c7..f47f0d905b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,26 @@ <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ --> -<!-- latest_release 14.0.60 --> -## [v14.0.60](https://github.com/chef/chef/tree/v14.0.60) (2018-02-19) +<!-- latest_release 14.0.71 --> +## [v14.0.71](https://github.com/chef/chef/tree/v14.0.71) (2018-02-21) #### Merged Pull Requests -- registry_key: Add sensitive property support for suppressing output (fixes #5695) [#6496](https://github.com/chef/chef/pull/6496) ([shoekstra](https://github.com/shoekstra)) +- Disable sudo on unit tests [#6879](https://github.com/chef/chef/pull/6879) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- latest_release --> <!-- release_rollup since=13.7.16 --> ### Changes since 13.7.16 release #### Merged Pull Requests +- Disable sudo on unit tests [#6879](https://github.com/chef/chef/pull/6879) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 14.0.71 --> +- Add macos_user_defaults resource from mac_os_x cookbook [#6878](https://github.com/chef/chef/pull/6878) ([tas50](https://github.com/tas50)) <!-- 14.0.70 --> +- updating paranoid to verify_host_key [#6869](https://github.com/chef/chef/pull/6869) ([tarcinil](https://github.com/tarcinil)) <!-- 14.0.69 --> +- make sure all proxy settings are dealt with [#6875](https://github.com/chef/chef/pull/6875) ([thommay](https://github.com/thommay)) <!-- 14.0.68 --> +- fix chefstyle [#6874](https://github.com/chef/chef/pull/6874) ([thommay](https://github.com/thommay)) <!-- 14.0.67 --> +- check identifier to resolve exported cookbooks by chef export [#6859](https://github.com/chef/chef/pull/6859) ([sawanoboly](https://github.com/sawanoboly)) <!-- 14.0.66 --> +- Add ohai_hint resource from ohai cookbook [#6793](https://github.com/chef/chef/pull/6793) ([tas50](https://github.com/tas50)) <!-- 14.0.65 --> +- Add powershell_package source param [#6843](https://github.com/chef/chef/pull/6843) ([Happycoil](https://github.com/Happycoil)) <!-- 14.0.64 --> +- Add new Redhat Subscription Manager resources [#6827](https://github.com/chef/chef/pull/6827) ([tas50](https://github.com/tas50)) <!-- 14.0.63 --> +- fix ohai tests after require_plugin removal [#6867](https://github.com/chef/chef/pull/6867) ([thommay](https://github.com/thommay)) <!-- 14.0.62 --> +- Add hostname resource from chef_hostname cookbook [#6795](https://github.com/chef/chef/pull/6795) ([tas50](https://github.com/tas50)) <!-- 14.0.61 --> - registry_key: Add sensitive property support for suppressing output (fixes #5695) [#6496](https://github.com/chef/chef/pull/6496) ([shoekstra](https://github.com/shoekstra)) <!-- 14.0.60 --> - Use the updated inspec gem - 1.51.18 [#6845](https://github.com/chef/chef/pull/6845) ([tas50](https://github.com/tas50)) <!-- 14.0.59 --> - add Chef::NodeMap#delete_class API [#6846](https://github.com/chef/chef/pull/6846) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 14.0.58 --> diff --git a/Gemfile.lock b/Gemfile.lock index 8d83200775..b21f28e410 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -35,10 +35,10 @@ GIT PATH remote: . specs: - chef (14.0.60) + chef (14.0.71) addressable bundler (>= 1.10) - chef-config (= 14.0.60) + chef-config (= 14.0.71) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -52,7 +52,7 @@ PATH mixlib-log (~> 1.3) mixlib-shellout (~> 2.0) net-sftp (~> 2.1, >= 2.1.2) - net-ssh (>= 2.9, < 5.0) + net-ssh (~> 4.2) net-ssh-multi (~> 1.2, >= 1.2.1) ohai (~> 14.0) plist (~> 3.2) @@ -65,10 +65,10 @@ PATH specinfra (~> 2.10) syslog-logger (~> 1.6) uuidtools (~> 2.1.5) - chef (14.0.60-universal-mingw32) + chef (14.0.71-universal-mingw32) addressable bundler (>= 1.10) - chef-config (= 14.0.60) + chef-config (= 14.0.71) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -83,7 +83,7 @@ PATH mixlib-log (~> 1.3) mixlib-shellout (~> 2.0) net-sftp (~> 2.1, >= 2.1.2) - net-ssh (>= 2.9, < 5.0) + net-ssh (~> 4.2) net-ssh-multi (~> 1.2, >= 1.2.1) ohai (~> 14.0) plist (~> 3.2) @@ -110,7 +110,7 @@ PATH PATH remote: chef-config specs: - chef-config (14.0.60) + chef-config (14.0.71) addressable fuzzyurl mixlib-config (~> 2.0) diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index eeec513a3f..0000000000 --- a/ROADMAP.md +++ /dev/null @@ -1,11 +0,0 @@ -# Roadmap - -This file provides direction for the project as set forth by [RFC030#Roadmap](https://github.com/chef/chef-rfc/blob/master/rfc030-maintenance-policy.md#roadmap). - -It is drafted by the Project Lead and the Lieutenants, with input from Maintainers and Contributors. - -## 2016 Q1 -* Windows - core windows_feature - - Move windows_feature from Windows cookbook, add caching -* Windows - knife windows bootstrap, knife windows winrm in core - - Migrate Windows bootstrapping functionality into core @@ -1 +1 @@ -14.0.60
\ No newline at end of file +14.0.71
\ No newline at end of file diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb index b378970758..44c07a0d8d 100644 --- a/chef-config/lib/chef-config/version.rb +++ b/chef-config/lib/chef-config/version.rb @@ -21,7 +21,7 @@ module ChefConfig CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__) - VERSION = "14.0.60" + VERSION = "14.0.71" end # diff --git a/chef-config/spec/unit/config_spec.rb b/chef-config/spec/unit/config_spec.rb index f5e9a914c9..41b4382cf0 100644 --- a/chef-config/spec/unit/config_spec.rb +++ b/chef-config/spec/unit/config_spec.rb @@ -852,9 +852,13 @@ RSpec.describe ChefConfig::Config do before(:all) do @original_env = ENV.to_hash ENV["http_proxy"] = nil + ENV["HTTP_PROXY"] = nil ENV["https_proxy"] = nil + ENV["HTTPS_PROXY"] = nil ENV["ftp_proxy"] = nil + ENV["FTP_PROXY"] = nil ENV["no_proxy"] = nil + ENV["NO_PROXY"] = nil end after(:all) do diff --git a/chef.gemspec b/chef.gemspec index 9dd85d74c6..352ce5dab0 100644 --- a/chef.gemspec +++ b/chef.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |s| s.add_dependency "ohai", "~> 14.0" s.add_dependency "ffi-yajl", "~> 2.2" - s.add_dependency "net-ssh", ">= 2.9", "< 5.0" + s.add_dependency "net-ssh", "~> 4.2" s.add_dependency "net-ssh-multi", "~> 1.2", ">= 1.2.1" s.add_dependency "net-sftp", "~> 2.1", ">= 2.1.2" s.add_dependency "highline", "~> 1.6", ">= 1.6.9" diff --git a/ci/verify-chef.sh b/ci/verify-chef.sh index 528152b3b6..3a9bcf2111 100755 --- a/ci/verify-chef.sh +++ b/ci/verify-chef.sh @@ -8,6 +8,9 @@ export TMPDIR sudo rm -rf $TMPDIR mkdir -p $TMPDIR +# Verify that we kill any orphaned test processes. Kill any orphaned rspec processes. +ps ax | egrep 'rspec' | grep -v grep | awk '{ print $1 }' | xargs sudo kill -s KILL || true + # $PROJECT_NAME is set by Jenkins, this allows us to use the same script to verify # Chef and Angry Chef PATH=/opt/$PROJECT_NAME/bin:$PATH diff --git a/kitchen-tests/cookbooks/base/metadata.rb b/kitchen-tests/cookbooks/base/metadata.rb index 9d4e663bec..83d460a17b 100644 --- a/kitchen-tests/cookbooks/base/metadata.rb +++ b/kitchen-tests/cookbooks/base/metadata.rb @@ -10,10 +10,7 @@ gem "chef-sugar" depends "apt" depends "build-essential" -depends "chef-apt-docker" depends "chef-client" -depends "chef-yum-docker" -depends "chef_hostname" depends "logrotate" depends "multipackage" depends "nscd" diff --git a/kitchen-tests/cookbooks/base/recipes/default.rb b/kitchen-tests/cookbooks/base/recipes/default.rb index e2d92cadc4..62823c1d37 100644 --- a/kitchen-tests/cookbooks/base/recipes/default.rb +++ b/kitchen-tests/cookbooks/base/recipes/default.rb @@ -44,9 +44,6 @@ include_recipe "chef-client::delete_validation" include_recipe "chef-client::config" include_recipe "chef-client" -include_recipe "chef-apt-docker" -include_recipe "chef-yum-docker" - include_recipe "openssh" include_recipe "nscd" diff --git a/lib/chef/api_client/registration.rb b/lib/chef/api_client/registration.rb index e61ef4a160..27e1f18c17 100644 --- a/lib/chef/api_client/registration.rb +++ b/lib/chef/api_client/registration.rb @@ -70,15 +70,15 @@ class Chef end def assert_destination_writable! - if !File.exists?(File.dirname(destination)) + abs_path = File.expand_path(destination) + if !File.exists?(File.dirname(abs_path)) begin - FileUtils.mkdir_p(File.dirname(destination)) + FileUtils.mkdir_p(File.dirname(abs_path)) rescue Errno::EACCES - raise Chef::Exceptions::CannotWritePrivateKey, "I can't write your private key to #{abs_path} - check permissions?" + raise Chef::Exceptions::CannotWritePrivateKey, "I can't create the configuration directory at #{File.dirname(abs_path)} - check permissions?" end end - if (File.exists?(destination) && !File.writable?(destination)) || !File.writable?(File.dirname(destination)) - abs_path = File.expand_path(destination) + if (File.exists?(abs_path) && !File.writable?(abs_path)) || !File.writable?(File.dirname(abs_path)) raise Chef::Exceptions::CannotWritePrivateKey, "I can't write your private key to #{abs_path} - check permissions?" end end diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb index 32530925d5..0834e5f037 100644 --- a/lib/chef/application/client.rb +++ b/lib/chef/application/client.rb @@ -345,6 +345,8 @@ class Chef::Application::Client < Chef::Application tarball_path = File.join(Chef::Config.chef_repo_path, "recipes.tgz") fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path) Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/) + config_path = File.join(Chef::Config.chef_repo_path, ".chef/config.rb") + Chef::Config.from_string(IO.read(config_path), config_path) if File.file?(config_path) end end diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb index 4f248625b3..cdb793f808 100644 --- a/lib/chef/chef_fs/chef_fs_data_store.rb +++ b/lib/chef/chef_fs/chef_fs_data_store.rb @@ -309,7 +309,10 @@ class Chef elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 3 with_entry([path[0]]) do |entry| cookbook_type = path[0] - cookbook_entry = entry.children.select { |child| child.chef_object.full_name == "#{path[1]}-#{path[2]}" }[0] + cookbook_entry = entry.children.select do |child| + child.chef_object.full_name == "#{path[1]}-#{path[2]}" || + (child.chef_object.name.to_s == path[1] && child.chef_object.identifier == path[2]) + end[0] raise ChefZero::DataStore::DataNotFoundError.new(path) if cookbook_entry.nil? result = nil begin diff --git a/lib/chef/knife/configure.rb b/lib/chef/knife/configure.rb index 10ae62b6c9..b277a14a3e 100644 --- a/lib/chef/knife/configure.rb +++ b/lib/chef/knife/configure.rb @@ -131,9 +131,7 @@ EOH def guess_servername o = Ohai::System.new - o.load_plugins - o.require_plugin "os" - o.require_plugin "hostname" + o.all_plugins(%w{ os hostname fqdn }) o[:fqdn] || o[:machinename] || o[:hostname] || "localhost" end diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb index 885ebc4faa..e02ea4ae1d 100644 --- a/lib/chef/knife/ssh.rb +++ b/lib/chef/knife/ssh.rb @@ -273,7 +273,7 @@ class Chef opts[:port] = port unless port.nil? opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug if !config[:host_key_verify] - opts[:paranoid] = false + opts[:verify_host_key] = false opts[:user_known_hosts_file] = "/dev/null" end if ssh_config[:keepalive] diff --git a/lib/chef/provider/ifconfig/debian.rb b/lib/chef/provider/ifconfig/debian.rb index 369c222b7a..e1e978fdde 100644 --- a/lib/chef/provider/ifconfig/debian.rb +++ b/lib/chef/provider/ifconfig/debian.rb @@ -36,11 +36,11 @@ class Chef <% if new_resource.onboot == "yes" %>auto <%= new_resource.device %><% end %> <% case new_resource.bootproto when "dhcp" %> -iface <%= new_resource.device %> inet dhcp +iface <%= new_resource.device %> <%= new_resource.family %> dhcp <% when "bootp" %> -iface <%= new_resource.device %> inet bootp +iface <%= new_resource.device %> <%= new_resource.family %> bootp <% else %> -iface <%= new_resource.device %> inet static +iface <%= new_resource.device %> <%= new_resource.family %> static <% if new_resource.target %>address <%= new_resource.target %><% end %> <% if new_resource.mask %>netmask <%= new_resource.mask %><% end %> <% if new_resource.network %>network <%= new_resource.network %><% end %> diff --git a/lib/chef/provider/package/powershell.rb b/lib/chef/provider/package/powershell.rb index 9111869c2b..f553aada0a 100644 --- a/lib/chef/provider/package/powershell.rb +++ b/lib/chef/provider/package/powershell.rb @@ -53,7 +53,7 @@ class Chef # Installs the package specified with the version passed else latest version will be installed def install_package(names, versions) names.each_with_index do |name, index| - powershell_out("Install-Package '#{name}' -Force -ForceBootstrap -RequiredVersion #{versions[index]}", timeout: new_resource.timeout) + powershell_out(build_powershell_command("Install-Package '#{name}'", versions[index]), timeout: new_resource.timeout) end end @@ -61,11 +61,11 @@ class Chef def remove_package(names, versions) names.each_with_index do |name, index| if versions && !versions[index].nil? - powershell_out("Uninstall-Package '#{name}' -Force -ForceBootstrap -RequiredVersion #{versions[index]}", timeout: new_resource.timeout) + powershell_out(build_powershell_command("Uninstall-Package '#{name}'", versions[index]), timeout: new_resource.timeout) else version = "0" until version.empty? - version = powershell_out("(Uninstall-Package '#{name}' -Force -ForceBootstrap).Version", timeout: new_resource.timeout).stdout.strip + version = powershell_out(build_powershell_command("Uninstall-Package '#{name}'"), timeout: new_resource.timeout).stdout.strip unless version.empty? Chef::Log.info("Removed package '#{name}' with version #{version}") end @@ -79,9 +79,9 @@ class Chef versions = [] new_resource.package_name.each_with_index do |name, index| version = if new_resource.version && !new_resource.version[index].nil? - powershell_out("(Find-Package '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force).Version", timeout: new_resource.timeout).stdout.strip + powershell_out(build_powershell_command("Find-Package '#{name}'", new_resource.version[index]), timeout: new_resource.timeout).stdout.strip else - powershell_out("(Find-Package '#{name}' -ForceBootstrap -Force).Version", timeout: new_resource.timeout).stdout.strip + powershell_out(build_powershell_command("Find-Package '#{name}'"), timeout: new_resource.timeout).stdout.strip end if version.empty? version = nil @@ -96,9 +96,9 @@ class Chef version_list = [] new_resource.package_name.each_with_index do |name, index| version = if new_resource.version && !new_resource.version[index].nil? - powershell_out("(Get-Package -Name '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force).Version", timeout: new_resource.timeout).stdout.strip + powershell_out(build_powershell_command("Get-Package '#{name}'", new_resource.version[index]), timeout: new_resource.timeout).stdout.strip else - powershell_out("(Get-Package -Name '#{name}' -ForceBootstrap -Force).Version", timeout: new_resource.timeout).stdout.strip + powershell_out(build_powershell_command("Get-Package '#{name}'"), timeout: new_resource.timeout).stdout.strip end if version.empty? version = nil @@ -108,6 +108,21 @@ class Chef version_list end + def build_powershell_command(command, version = nil) + command = [command] unless command.is_a?(Array) + command.unshift("(") + %w{-Force -ForceBootstrap}.each do |arg| + command.push(arg) + end + command.push("-RequiredVersion #{version}") if version + command.push("-Source #{new_resource.source}") if new_resource.source && command[1] =~ Regexp.union(/Install-Package/, /Find-Package/) + command.push(").Version") + command.join(" ") + end + + def check_resource_semantics! + # This validation method from Chef::Provider::Package does not apply here, so no-op it. + end end end end diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb index 51e38834b6..ea0c9c6183 100644 --- a/lib/chef/resource/apt_package.rb +++ b/lib/chef/resource/apt_package.rb @@ -21,11 +21,12 @@ require "chef/provider/package/apt" class Chef class Resource - # Use the apt_package resource to manage packages on Debian and Ubuntu platforms. class AptPackage < Chef::Resource::Package resource_name :apt_package provides :package, os: "linux", platform_family: "debian" + description "Use the apt_package resource to manage packages on Debian and Ubuntu platforms." + property :default_release, String, desired_state: false property :overwrite_config_files, [TrueClass, FalseClass], default: false diff --git a/lib/chef/resource/apt_preference.rb b/lib/chef/resource/apt_preference.rb index 87c5a5a016..442d85a78a 100644 --- a/lib/chef/resource/apt_preference.rb +++ b/lib/chef/resource/apt_preference.rb @@ -20,14 +20,16 @@ require "chef/resource" class Chef class Resource - # The apt_preference resource allows for the creation of APT preference files. Preference files are used to control - # which package versions and sources are prioritized during installation. - # # @since 13.3 class AptPreference < Chef::Resource resource_name :apt_preference provides :apt_preference + description "The apt_preference resource allows for the creation of APT preference"\ + " files. Preference files are used to control which package versions and"\ + " sources are prioritized during installation." + introduced "13.3" + property :package_name, String, name_property: true, regex: [/^([a-z]|[A-Z]|[0-9]|_|-|\.|\*|\+)+$/] property :glob, String property :pin, String, required: true diff --git a/lib/chef/resource/apt_repository.rb b/lib/chef/resource/apt_repository.rb index 5b81112cbe..6b044afe27 100644 --- a/lib/chef/resource/apt_repository.rb +++ b/lib/chef/resource/apt_repository.rb @@ -20,14 +20,14 @@ require "chef/resource" class Chef class Resource - # Use the apt_repository resource to specify additional APT repositories. Adding a new repository will update - # APT package cache immediately. - # - # @since 12.9 class AptRepository < Chef::Resource resource_name :apt_repository provides :apt_repository + description "Use the apt_repository resource to specify additional APT repositories."\ + " Adding a new repository will update APT package cache immediately." + introduced "12.9" + property :repo_name, String, name_property: true property :uri, String property :distribution, [ String, nil, false ], default: lazy { node["lsb"]["codename"] }, coerce: proc { |x| x ? x : nil } diff --git a/lib/chef/resource/apt_update.rb b/lib/chef/resource/apt_update.rb index 0349614ad2..378edd2170 100644 --- a/lib/chef/resource/apt_update.rb +++ b/lib/chef/resource/apt_update.rb @@ -20,13 +20,14 @@ require "chef/resource" class Chef class Resource - # Use the apt_update resource to manage APT repository updates on Debian and Ubuntu platforms. - # - # @since 12.7 class AptUpdate < Chef::Resource resource_name :apt_update provides :apt_update + description "Use the apt_update resource to manage APT repository updates on"\ + " Debian and Ubuntu platforms." + introduced "12.7" + # allow bare apt_update with no name property :name, String, default: "" property :frequency, Integer, default: 86_400 diff --git a/lib/chef/resource/bash.rb b/lib/chef/resource/bash.rb index ebc4a7790b..03fdd0e396 100644 --- a/lib/chef/resource/bash.rb +++ b/lib/chef/resource/bash.rb @@ -21,11 +21,13 @@ require "chef/provider/script" class Chef class Resource - # Use the bash resource to execute scripts using the Bash interpreter. This resource may also use any of the actions - # and properties that are available to the execute resource. Commands that are executed with this resource are (by - # their nature) not idempotent, as they are typically unique to the environment in which they are run. Use not_if - # and only_if to guard this resource for idempotence. class Bash < Chef::Resource::Script + description "Use the bash resource to execute scripts using the Bash interpreter."\ + " This resource may also use any of the actions and properties that are"\ + " available to the execute resource. Commands that are executed with this"\ + " resource are (by their nature) not idempotent, as they are typically"\ + " unique to the environment in which they are run. Use not_if and only_if"\ + " to guard this resource for idempotence." def initialize(name, run_context = nil) super diff --git a/lib/chef/resource/batch.rb b/lib/chef/resource/batch.rb index b3c7b17cef..1c666a46ba 100644 --- a/lib/chef/resource/batch.rb +++ b/lib/chef/resource/batch.rb @@ -20,15 +20,17 @@ require "chef/resource/windows_script" class Chef class Resource - # Use the batch resource to execute a batch script using the cmd.exe interpreter on Windows. The batch resource - # creates and executes a temporary file (similar to how the script resource behaves), rather than running the - # command inline. Commands that are executed with this resource are (by their nature) not idempotent, as they are - # typically unique to the environment in which they are run. Use not_if and only_if to guard this resource for - # idempotence. class Batch < Chef::Resource::WindowsScript - provides :batch, os: "windows" + description "Use the batch resource to execute a batch script using the cmd.exe"\ + " interpreter on Windows. The batch resource creates and executes a"\ + " temporary file (similar to how the script resource behaves), rather"\ + " than running the command inline. Commands that are executed with this"\ + " resource are (by their nature) not idempotent, as they are typically"\ + " unique to the environment in which they are run. Use not_if and only_if"\ + " to guard this resource for idempotence." + def initialize(name, run_context = nil) super(name, run_context, nil, "cmd.exe") end diff --git a/lib/chef/resource/bff_package.rb b/lib/chef/resource/bff_package.rb index d91777cb74..f67d6d253e 100644 --- a/lib/chef/resource/bff_package.rb +++ b/lib/chef/resource/bff_package.rb @@ -21,11 +21,12 @@ require "chef/provider/package/aix" class Chef class Resource - # Use the bff_package resource to manage packages for the AIX platform using the installp utility. When a package is - # installed from a local file, it must be added to the node using the remote_file or cookbook_file resources. - # - # @since 12.0 class BffPackage < Chef::Resource::Package + description "Use the bff_package resource to manage packages for the AIX platform"\ + " using the installp utility. When a package is installed from a local"\ + " file, it must be added to the node using the remote_file or cookbook_file"\ + " resources." + introduced "12.0" end end end diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb index 5d2c5555be..1ccc4311b3 100644 --- a/lib/chef/resource/breakpoint.rb +++ b/lib/chef/resource/breakpoint.rb @@ -20,16 +20,19 @@ require "chef/resource" class Chef class Resource - # Use the breakpoint resource to add breakpoints to recipes. Run the chef-shell in chef-client mode, and then use - # those breakpoints to debug recipes. Breakpoints are ignored by the chef-client during an actual chef-client run. - # That said, breakpoints are typically used to debug recipes only when running them in a non-production environment, - # after which they are removed from those recipes before the parent cookbook is uploaded to the Chef server. - # - # @since 12.0 class Breakpoint < Chef::Resource provides :breakpoint resource_name :breakpoint + description "Use the breakpoint resource to add breakpoints to recipes. Run the"\ + " chef-shell in chef-client mode, and then use those breakpoints to debug"\ + " recipes. Breakpoints are ignored by the chef-client during an actual"\ + " chef-client run. That said, breakpoints are typically used to debug"\ + " recipes only when running them in a non-production environment, after"\ + " which they are removed from those recipes before the parent cookbook is"\ + " uploaded to the Chef server." + introduced "12.0" + default_action :break def initialize(action = "break", *args) diff --git a/lib/chef/resource/cab_package.rb b/lib/chef/resource/cab_package.rb index 8f3b3038c4..06c84fa559 100644 --- a/lib/chef/resource/cab_package.rb +++ b/lib/chef/resource/cab_package.rb @@ -21,15 +21,16 @@ require "chef/mixin/uris" class Chef class Resource - # Use the cab_package resource to install or remove Microsoft Windows cabinet (.cab) packages. - # - # @since 12.15 class CabPackage < Chef::Resource::Package include Chef::Mixin::Uris resource_name :cab_package provides :cab_package, os: "windows" + description "Use the cab_package resource to install or remove Microsoft Windows"\ + " cabinet (.cab) packages." + introduced "12.15" + allowed_actions :install, :remove property :source, String, diff --git a/lib/chef/resource/chocolatey_package.rb b/lib/chef/resource/chocolatey_package.rb index 58bcab8b39..c5a5d827a2 100644 --- a/lib/chef/resource/chocolatey_package.rb +++ b/lib/chef/resource/chocolatey_package.rb @@ -20,14 +20,14 @@ require "chef/resource/package" class Chef class Resource - # Use the chocolatey_package resource to manage packages using Chocolatey on the Microsoft Windows platform. - # - # @since 12.7 class ChocolateyPackage < Chef::Resource::Package - resource_name :chocolatey_package provides :chocolatey_package, os: "windows" + description "Use the chocolatey_package resource to manage packages using Chocolatey"\ + " on the Microsoft Windows platform." + introduced "12.7" + allowed_actions :install, :upgrade, :remove, :uninstall, :purge, :reconfig # windows can't take Array options yet diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb index 8c3de119e9..593cb5e137 100644 --- a/lib/chef/resource/cookbook_file.rb +++ b/lib/chef/resource/cookbook_file.rb @@ -24,20 +24,23 @@ require "chef/mixin/securable" class Chef class Resource - # Use the cookbook_file resource to transfer files from a sub-directory of COOKBOOK_NAME/files/ to a specified path - # located on a host that is running the chef-client. The file is selected according to file specificity, which allows - # different source files to be used based on the hostname, host platform (operating system, distro, or as appropriate), - # or platform version. Files that are located in the COOKBOOK_NAME/files/default sub-directory may be used on any - # platform. - # - # During a chef-client run, the checksum for each local file is calculated and then compared against the checksum for - # the same file as it currently exists in the cookbook on the Chef server. A file is not transferred when the checksums - # match. Only files that require an update are transferred from the Chef server to a node. class CookbookFile < Chef::Resource::File include Chef::Mixin::Securable resource_name :cookbook_file + description "Use the cookbook_file resource to transfer files from a sub-directory"\ + " of COOKBOOK_NAME/files/ to a specified path located on a host that is"\ + " running the chef-client. The file is selected according to file specificity,"\ + " which allows different source files to be used based on the hostname, host"\ + " platform (operating system, distro, or as appropriate), or platform version."\ + " Files that are located in the COOKBOOK_NAME/files/default sub-directory may be"\ + " used on any platform.\n\n"\ + "During a chef-client run, the checksum for each local file is calculated and then"\ + " compared against the checksum for the same file as it currently exists in the"\ + " cookbook on the Chef server. A file is not transferred when the checksums match."\ + " Only files that require an update are transferred from the Chef server to a node." + property :source, [ String, Array ], default: lazy { ::File.basename(name) } property :cookbook, String diff --git a/lib/chef/resource/cron.rb b/lib/chef/resource/cron.rb index 2b70be7bb8..72023c31ed 100644 --- a/lib/chef/resource/cron.rb +++ b/lib/chef/resource/cron.rb @@ -21,9 +21,10 @@ require "chef/resource" class Chef class Resource - # Use the cron resource to manage cron entries for time-based job scheduling. Properties for a schedule will default - # to * if not provided. The cron resource requires access to a crontab program, typically cron. class Cron < Chef::Resource + description "Use the cron resource to manage cron entries for time-based job scheduling."\ + " Properties for a schedule will default to * if not provided. The cron resource"\ + " requires access to a crontab program, typically cron." identity_attr :command diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb index ef302af6c0..0938a19cb1 100644 --- a/lib/chef/resource/csh.rb +++ b/lib/chef/resource/csh.rb @@ -21,11 +21,13 @@ require "chef/provider/script" class Chef class Resource - # Use the csh resource to execute scripts using the csh interpreter. This resource may also use any of the actions - # and properties that are available to the execute resource. Commands that are executed with this resource are (by - # their nature) not idempotent, as they are typically unique to the environment in which they are run. Use not_if - # and only_if to guard this resource for idempotence. class Csh < Chef::Resource::Script + description "Use the csh resource to execute scripts using the csh interpreter."\ + " This resource may also use any of the actions and properties that are"\ + " available to the execute resource. Commands that are executed with this"\ + " resource are (by their nature) not idempotent, as they are typically"\ + " unique to the environment in which they are run. Use not_if and only_if"\ + " to guard this resource for idempotence." def initialize(name, run_context = nil) super diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb index b989b3ecde..1f18a4b951 100644 --- a/lib/chef/resource/directory.rb +++ b/lib/chef/resource/directory.rb @@ -23,13 +23,16 @@ require "chef/mixin/securable" class Chef class Resource - # Use the directory resource to manage a directory, which is a hierarchy of folders that comprises all of the - # information stored on a computer. The root directory is the top-level, under which the rest of the directory - # is organized. The directory resource uses the name property to specify the path to a location in a directory. - # Typically, permission to access that location in the directory is required. class Directory < Chef::Resource resource_name :directory + description "Use the directory resource to manage a directory, which is a hierarchy"\ + " of folders that comprises all of the information stored on a computer."\ + " The root directory is the top-level, under which the rest of the directory"\ + " is organized. The directory resource uses the name property to specify the"\ + " path to a location in a directory. Typically, permission to access that"\ + " location in the directory is required." + state_attrs :group, :mode, :owner include Chef::Mixin::Securable diff --git a/lib/chef/resource/dnf_package.rb b/lib/chef/resource/dnf_package.rb index 0e09d90d43..08d19ff6b9 100644 --- a/lib/chef/resource/dnf_package.rb +++ b/lib/chef/resource/dnf_package.rb @@ -21,17 +21,20 @@ require "chef/mixin/shell_out" class Chef class Resource - # Use the dnf_package resource to install, upgrade, and remove packages with DNF for Fedora platforms. The dnf_package - # resource is able to resolve provides data for packages much like DNF can do when it is run from the command line. - # This allows a variety of options for installing packages, like minimum versions, virtual provides, and library names. - # - # @since 12.18 class DnfPackage < Chef::Resource::Package extend Chef::Mixin::Which extend Chef::Mixin::ShellOut resource_name :dnf_package + description "Use the dnf_package resource to install, upgrade, and remove packages"\ + " with DNF for Fedora platforms. The dnf_package resource is able to"\ + " resolve provides data for packages much like DNF can do when it is"\ + " run from the command line. This allows a variety of options for"\ + " installing packages, like minimum versions, virtual provides,"\ + " and library names." + introduced "12.18" + allowed_actions :install, :upgrade, :remove, :purge, :reconfig, :lock, :unlock, :flush_cache # all rhel variants >= 8 will use DNF diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb index c73fc506ad..488af8e1c9 100644 --- a/lib/chef/resource/dpkg_package.rb +++ b/lib/chef/resource/dpkg_package.rb @@ -20,12 +20,14 @@ require "chef/resource/package" class Chef class Resource - # Use the dpkg_package resource to manage packages for the dpkg platform. When a package is installed from a local - # file, it must be added to the node using the remote_file or cookbook_file resources. class DpkgPackage < Chef::Resource::Package resource_name :dpkg_package provides :dpkg_package, os: "linux" + description "Use the dpkg_package resource to manage packages for the dpkg platform."\ + " When a package is installed from a local file, it must be added to the"\ + " node using the remote_file or cookbook_file resources." + property :source, [ String, Array, nil ] end end diff --git a/lib/chef/resource/dsc_resource.rb b/lib/chef/resource/dsc_resource.rb index 0840b9bca1..95ee32c946 100644 --- a/lib/chef/resource/dsc_resource.rb +++ b/lib/chef/resource/dsc_resource.rb @@ -19,14 +19,15 @@ require "chef/dsl/powershell" class Chef class Resource - # The dsc_resource resource allows any DSC resource to be used in a Chef recipe, as well as any custom resources - # that have been added to your Windows PowerShell environment. Microsoft frequently adds new resources to the DSC - # resource collection. - # - # @since 12.2 class DscResource < Chef::Resource provides :dsc_resource, os: "windows" + description "The dsc_resource resource allows any DSC resource to be used in a"\ + " Chef recipe, as well as any custom resources that have been added"\ + " to your Windows PowerShell environment. Microsoft frequently adds"\ + " new resources to the DSC resource collection." + introduced "12.2" + # This class will check if the object responds to # to_text. If it does, it will call that as opposed # to inspect. This is useful for properties that hold diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb index cea52e422b..45372c091a 100644 --- a/lib/chef/resource/dsc_script.rb +++ b/lib/chef/resource/dsc_script.rb @@ -21,17 +21,21 @@ require "chef/dsl/powershell" class Chef class Resource - # Many DSC resources are comparable to built-in Chef resources. For example, both DSC and Chef have file, package, - # and service resources. The dsc_script resource is most useful for those DSC resources that do not have a direct - # comparison to a resource in Chef, such as the Archive resource, a custom DSC resource, an existing DSC script - # that performs an important task, and so on. Use the dsc_script resource to embed the code that defines a DSC - # configuration directly within a Chef recipe. class DscScript < Chef::Resource include Chef::DSL::Powershell resource_name :dsc_script provides :dsc_script, os: "windows" + description "Many DSC resources are comparable to built-in Chef resources. For"\ + " example, both DSC and Chef have file, package, and service resources."\ + " The dsc_script resource is most useful for those DSC resources that"\ + " do not have a direct comparison to a resource in Chef, such as the"\ + " Archive resource, a custom DSC resource, an existing DSC script"\ + " that performs an important task, and so on. Use the dsc_script resource"\ + " to embed the code that defines a DSC configuration directly within a"\ + " Chef recipe." + default_action :run def initialize(name, run_context = nil) diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index 616195deee..0c1b187ed0 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -22,13 +22,15 @@ require "chef/provider/execute" class Chef class Resource - # Use the execute resource to execute a single command. Commands that are executed with this resource are (by their - # nature) not idempotent, as they are typically unique to the environment in which they are run. Use not_if and only_if - # to guard this resource for idempotence. class Execute < Chef::Resource identity_attr :command + description "Use the execute resource to execute a single command. Commands that"\ + " are executed with this resource are (by their nature) not idempotent,"\ + " as they are typically unique to the environment in which they are run."\ + " Use not_if and only_if to guard this resource for idempotence." + # The ResourceGuardInterpreter wraps a resource's guards in another resource. That inner resource # needs to behave differently during (for example) why_run mode, so we flag it here. For why_run mode # we still want to execute the guard resource even if we are not executing the wrapping resource. diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb index 787992fc24..98341ff940 100644 --- a/lib/chef/resource/file.rb +++ b/lib/chef/resource/file.rb @@ -25,10 +25,11 @@ require "pathname" class Chef class Resource - # Use the file resource to manage files directly on a node. class File < Chef::Resource include Chef::Mixin::Securable + description "Use the file resource to manage files directly on a node." + if Platform.windows? # Use Windows rights instead of standard *nix permissions state_attrs :checksum, :rights, :deny_rights diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb index caaba29129..d16355d027 100644 --- a/lib/chef/resource/freebsd_package.rb +++ b/lib/chef/resource/freebsd_package.rb @@ -26,13 +26,14 @@ require "chef/mixin/shell_out" class Chef class Resource - # Use the freebsd_package resource to manage packages for the FreeBSD platform. class FreebsdPackage < Chef::Resource::Package include Chef::Mixin::ShellOut resource_name :freebsd_package provides :package, platform: "freebsd" + description "Use the freebsd_package resource to manage packages for the FreeBSD platform." + # make sure we assign the appropriate underlying providers based on what # package managers exist on this FreeBSD system or the source of the package # diff --git a/lib/chef/resource/gem_package.rb b/lib/chef/resource/gem_package.rb index 8e3a426035..1f9bae614d 100644 --- a/lib/chef/resource/gem_package.rb +++ b/lib/chef/resource/gem_package.rb @@ -20,11 +20,14 @@ require "chef/resource/package" class Chef class Resource - # Use the gem_package resource to manage gem packages that are only included in recipes. When a package is installed - # from a local file, it must be added to the node using the remote_file or cookbook_file resources. class GemPackage < Chef::Resource::Package resource_name :gem_package + description "Use the gem_package resource to manage gem packages that are only"\ + " included in recipes. When a package is installed from a local file,"\ + " it must be added to the node using the remote_file or cookbook_file"\ + " resources." + # the source can either be a path to a package source like: # source /var/tmp/mygem-1.2.3.4.gem # or it can be a url rubygems source like: diff --git a/lib/chef/resource/git.rb b/lib/chef/resource/git.rb index ac4f027552..9f1702f715 100644 --- a/lib/chef/resource/git.rb +++ b/lib/chef/resource/git.rb @@ -20,10 +20,12 @@ require "chef/resource/scm" class Chef class Resource - # Use the git resource to manage source control resources that exist in a git repository. git version 1.6.5 (or higher) - # is required to use all of the functionality in the git resource. class Git < Chef::Resource::Scm + description "Use the git resource to manage source control resources that exist"\ + " in a git repository. git version 1.6.5 (or higher) is required to"\ + " use all of the functionality in the git resource." + def initialize(name, run_context = nil) super @additional_remotes = Hash[] diff --git a/lib/chef/resource/group.rb b/lib/chef/resource/group.rb index 69a3827a5c..79a234cb54 100644 --- a/lib/chef/resource/group.rb +++ b/lib/chef/resource/group.rb @@ -19,13 +19,12 @@ class Chef class Resource - # Use the group resource to manage a local group. class Group < Chef::Resource - identity_attr :group_name - state_attrs :members + description "Use the group resource to manage a local group." + allowed_actions :create, :remove, :modify, :manage default_action :create diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb index 6174a31079..dee132a1b4 100644 --- a/lib/chef/resource/homebrew_package.rb +++ b/lib/chef/resource/homebrew_package.rb @@ -23,13 +23,13 @@ require "chef/resource/package" class Chef class Resource - # Use the homebrew_package resource to manage packages for the macOS platform. - # - # @since 12.0 class HomebrewPackage < Chef::Resource::Package resource_name :homebrew_package provides :package, os: "darwin" + description "Use the homebrew_package resource to manage packages for the macOS platform." + introduced "12.0" + property :homebrew_user, [ String, Integer ] end diff --git a/lib/chef/resource/hostname.rb b/lib/chef/resource/hostname.rb new file mode 100644 index 0000000000..16986c09a3 --- /dev/null +++ b/lib/chef/resource/hostname.rb @@ -0,0 +1,252 @@ +class Chef + class Resource + # Sets the hostname and updates /etc/hosts on *nix systems + # @since 14.0.0 + class Hostname < Chef::Resource + provides :hostname + resource_name :hostname + + description "Sets the systems hostname, ensures that reboot will preserve the hostname, and re-runs the ohai plugin so the hostname will be available in subsequent cookbooks." + introduced "14.0" + + property :hostname, + String, + description: "The hostname if different than the resource's name", + name_property: true + + property :compile_time, + [ TrueClass, FalseClass ], + description: "Should the resource run at compile time or not.", + default: true + + property :ipaddress, + String, + description: "The ip address to use when configuring the hosts file", + default: lazy { node["ipaddress"] } + + property :aliases, + [ Array, nil ], + description: "An array of hostname aliases to use when configuring the hosts file", + default: nil + + property :windows_reboot, + [ TrueClass, FalseClass ], + description: "Should Windows nodes be rebooted upon changing the name so it can take effect", + default: true + + action_class do + def append_replacing_matching_lines(path, regex, string) + text = IO.read(path).split("\n") + text.reject! { |s| s =~ regex } + text += [ string ] + file path do + content text.join("\n") + "\n" + owner "root" + group node["root_group"] + mode "0644" + not_if { IO.read(path).split("\n").include?(string) } + end + end + + # read in the xml file used by Ec2ConfigService and update the Ec2SetComputerName + # setting to disable updating the computer name so we don't revert our change on reboot + # @return [String] + def updated_ec2_config_xml + begin + require "rexml/document" + config_file = 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml' + config = REXML::Document.new(::File.read(config_file)) + # find an element named State with a sibling element whose value is Ec2SetComputerName + REXML::XPath.each(config, "//Plugin/State[../Name/text() = 'Ec2SetComputerName']") do |element| + element.text = "Disabled" + end + rescue + return "" + end + config.to_s + end + end + + action :set do + description "Sets the node's hostname" + + ohai "reload hostname" do + plugin "hostname" + action :nothing + end + + if node["platform_family"] != "windows" + # set the hostname via /bin/hostname + declare_resource(:execute, "set hostname to #{new_resource.hostname}") do + command "/bin/hostname #{new_resource.hostname}" + not_if { shell_out!("hostname").stdout.chomp == new_resource.hostname } + notifies :reload, "ohai[reload hostname]" + end + + # make sure node['fqdn'] resolves via /etc/hosts + unless new_resource.ipaddress.nil? + newline = "#{new_resource.ipaddress} #{new_resource.hostname}" + newline << " #{new_resource.aliases.join(" ")}" if new_resource.aliases && !new_resource.aliases.empty? + newline << " #{new_resource.hostname[/[^\.]*/]}" + r = append_replacing_matching_lines("/etc/hosts", /^#{new_resource.ipaddress}\s+|\s+#{new_resource.hostname}\s+/, newline) + r.atomic_update false if docker? + r.notifies :reload, "ohai[reload hostname]" + end + + # setup the hostname to perist on a reboot + case + when ::File.exist?("/usr/sbin/scutil") + # darwin + declare_resource(:execute, "set HostName via scutil") do + command "/usr/sbin/scutil --set HostName #{new_resource.hostname}" + not_if { shell_out!("/usr/sbin/scutil --get HostName").stdout.chomp == new_resource.hostname } + notifies :reload, "ohai[reload hostname]" + end + declare_resource(:execute, "set ComputerName via scutil") do + command "/usr/sbin/scutil --set ComputerName #{new_resource.hostname}" + not_if { shell_out!("/usr/sbin/scutil --get ComputerName").stdout.chomp == new_resource.hostname } + notifies :reload, "ohai[reload hostname]" + end + shortname = new_resource.hostname[/[^\.]*/] + declare_resource(:execute, "set LocalHostName via scutil") do + command "/usr/sbin/scutil --set LocalHostName #{shortname}" + not_if { shell_out!("/usr/sbin/scutil --get LocalHostName").stdout.chomp == shortname } + notifies :reload, "ohai[reload hostname]" + end + when node["os"] == "linux" + case + when ::File.exist?("/usr/bin/hostnamectl") && !docker? + # use hostnamectl whenever we find it on linux (as systemd takes over the world) + # this must come before other methods like /etc/hostname and /etc/sysconfig/network + declare_resource(:execute, "hostnamectl set-hostname #{new_resource.hostname}") do + notifies :reload, "ohai[reload hostname]" + not_if { shell_out!("hostnamectl status", { :returns => [0, 1] }).stdout =~ /Static hostname:\s+#{new_resource.hostname}/ } + end + when ::File.exist?("/etc/hostname") + # debian family uses /etc/hostname + # arch also uses /etc/hostname + # the "platform: iox_xr, platform_family: wrlinux, os: linux" platform also hits this + # the "platform: nexus, platform_family: wrlinux, os: linux" platform also hits this + # this is also fallback for any linux systemd host in a docker container (where /usr/bin/hostnamectl will fail) + declare_resource(:file, "/etc/hostname") do + atomic_update false if docker? + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + when ::File.file?("/etc/sysconfig/network") + # older non-systemd RHEL/Fedora derived + append_replacing_matching_lines("/etc/sysconfig/network", /^HOSTNAME\s*=/, "HOSTNAME=#{new_resource.hostname}") + when ::File.exist?("/etc/HOSTNAME") + # SuSE/OpenSUSE uses /etc/HOSTNAME + declare_resource(:file, "/etc/HOSTNAME") do + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + when ::File.exist?("/etc/conf.d/hostname") + # Gentoo + declare_resource(:file, "/etc/conf.d/hostname") do + content "hostname=\"#{new_resource.hostname}\"\n" + owner "root" + group node["root_group"] + mode "0644" + end + else + # This is a failsafe for all other linux distributions where we set the hostname + # via /etc/sysctl.conf on reboot. This may get into a fight with other cookbooks + # that manage sysctls on linux. + append_replacing_matching_lines("/etc/sysctl.conf", /^\s+kernel\.hostname\s+=/, "kernel.hostname=#{new_resource.hostname}") + end + when ::File.exist?("/etc/rc.conf") + # *BSD systems with /etc/rc.conf + /etc/myname + append_replacing_matching_lines("/etc/rc.conf", /^\s+hostname\s+=/, "hostname=#{new_resource.hostname}") + + declare_resource(:file, "/etc/myname") do + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + when ::File.exist?("/etc/nodename") + # Solaris <= 5.10 systems prior to svccfg taking over this functionality (must come before svccfg handling) + declare_resource(:file, "/etc/nodename") do + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + # Solaris also has /etc/inet/hosts (copypasta alert) + unless new_resource.ipaddress.nil? + newline = "#{new_resource.ipaddress} #{new_resource.hostname}" + newline << " #{new_resource.aliases.join(" ")}" if new_resource.aliases && !new_resource.aliases.empty? + newline << " #{new_resource.hostname[/[^\.]*/]}" + r = append_replacing_matching_lines("/etc/inet/hosts", /^#{new_resource.ipaddress}\s+|\s+#{new_resource.hostname}\s+/, newline) + r.notifies :reload, "ohai[reload hostname]" + end + when ::File.exist?("/usr/sbin/svccfg") + # Solaris >= 5.11 systems using svccfg (must come after /etc/nodename handling) + declare_resource(:execute, "svccfg -s system/identity:node setprop config/nodename=\'#{new_resource.hostname}\'") do + notifies :run, "execute[svcadm refresh]", :immediately + notifies :run, "execute[svcadm restart]", :immediately + not_if { shell_out!("svccfg -s system/identity:node listprop config/nodename").stdout.chomp =~ /config\/nodename\s+astring\s+#{new_resource.hostname}/ } + end + declare_resource(:execute, "svcadm refresh") do + command "svcadm refresh system/identity:node" + action :nothing + end + declare_resource(:execute, "svcadm restart") do + command "svcadm restart system/identity:node" + action :nothing + end + else + raise "Do not know how to set hostname on os #{node["os"]}, platform #{node["platform"]},"\ + "platform_version #{node["platform_version"]}, platform_family #{node["platform_family"]}" + end + + else # windows + + # suppress EC2 config service from setting our hostname + if ::File.exist?('C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml') + xml_contents = updated_ec2_config_xml + if xml_contents.empty? + Chef::Log.warn('Unable to properly parse and update C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml contents. Skipping file update.') + else + declare_resource(:file, 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml') do + content xml_contents + end + end + end + + # update via netdom + declare_resource(:powershell_script, "set hostname") do + code <<-EOH + $sysInfo = Get-WmiObject -Class Win32_ComputerSystem + $sysInfo.Rename("#{new_resource.hostname}") + EOH + notifies :request_reboot, "reboot[setting hostname]" + not_if { Socket.gethostbyname(Socket.gethostname).first == new_resource.hostname } + end + + # reboot because $windows + declare_resource(:reboot, "setting hostname") do + reason "chef setting hostname" + action :nothing + only_if { new_resource.windows_reboot } + end + end + end + + # this resource forces itself to run at compile_time + def after_created + if compile_time + Array(action).each do |action| + run_action(action) + end + end + end + end + end +end diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb index 9d8fce9b22..d3b782ea12 100644 --- a/lib/chef/resource/http_request.rb +++ b/lib/chef/resource/http_request.rb @@ -22,12 +22,14 @@ require "chef/provider/http_request" class Chef class Resource - # Use the http_request resource to send an HTTP request (GET, PUT, POST, DELETE, HEAD, or OPTIONS) with an arbitrary - # message. This resource is often useful when custom callbacks are necessary. class HttpRequest < Chef::Resource identity_attr :url + description "Use the http_request resource to send an HTTP request (GET, PUT,"\ + " POST, DELETE, HEAD, or OPTIONS) with an arbitrary message. This"\ + " resource is often useful when custom callbacks are necessary." + default_action :get allowed_actions :get, :patch, :put, :post, :delete, :head, :options diff --git a/lib/chef/resource/ifconfig.rb b/lib/chef/resource/ifconfig.rb index e9ef47d95b..579a4eeedb 100644 --- a/lib/chef/resource/ifconfig.rb +++ b/lib/chef/resource/ifconfig.rb @@ -21,8 +21,6 @@ require "chef/resource" class Chef class Resource - # use the ifconfig resource to manage interfaces on *nix systems - # # @example set a static ip on eth1 # ifconfig '33.33.33.80' do # device 'eth1' @@ -30,6 +28,8 @@ class Chef class Ifconfig < Chef::Resource resource_name :ifconfig + description "Use the ifconfig resource to manage interfaces on *nix systems." + state_attrs :inet_addr, :mask default_action :add @@ -38,6 +38,7 @@ class Chef property :target, String, name_property: true property :hwaddr, String property :mask, String + property :family, String, default: "inet" property :inet_addr, String property :bcast, String property :mtu, String diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb index 296919dc1c..88a9f182d4 100644 --- a/lib/chef/resource/ips_package.rb +++ b/lib/chef/resource/ips_package.rb @@ -21,12 +21,13 @@ require "chef/provider/package/ips" class Chef class Resource - # Use the ips_package resource to manage packages (using Image Packaging System (IPS)) on the Solaris 11 platform. class IpsPackage < ::Chef::Resource::Package resource_name :ips_package provides :package, os: "solaris2" provides :ips_package, os: "solaris2" + description "Use the ips_package resource to manage packages (using Image Packaging System (IPS)) on the Solaris 11 platform." + allowed_actions :install, :remove, :upgrade property :accept_license, [ true, false ], default: false, desired_state: false diff --git a/lib/chef/resource/ksh.rb b/lib/chef/resource/ksh.rb index 8024f0d6bd..f0bc277d17 100644 --- a/lib/chef/resource/ksh.rb +++ b/lib/chef/resource/ksh.rb @@ -20,13 +20,14 @@ require "chef/resource/script" class Chef class Resource - # Use the ksh resource to execute scripts using the Korn shell (ksh) interpreter. This resource may also use any - # f the actions and properties that are available to the execute resource. Commands that are executed with this - # resource are (by their nature) not idempotent, as they are typically unique to the environment in which they are - # run. Use not_if and only_if to guard this resource for idempotence. - # - # @since 12.6 class Ksh < Chef::Resource::Script + description "Use the ksh resource to execute scripts using the Korn shell (ksh)"\ + " interpreter. This resource may also use any of the actions and properties"\ + " that are available to the execute resource. Commands that are executed"\ + " with this resource are (by their nature) not idempotent, as they are"\ + " typically unique to the environment in which they are run. Use not_if"\ + " and only_if to guard this resource for idempotence." + introduced "12.6" def initialize(name, run_context = nil) super diff --git a/lib/chef/resource/launchd.rb b/lib/chef/resource/launchd.rb index 121af1555c..bc1b7d48e8 100644 --- a/lib/chef/resource/launchd.rb +++ b/lib/chef/resource/launchd.rb @@ -20,13 +20,13 @@ require "chef/resource" class Chef class Resource - # Use the launchd resource to manage system-wide services (daemons) and per-user services (agents) on the macOS platform. - # - # @since 12.8 class Launchd < Chef::Resource resource_name :launchd provides :launchd, os: "darwin" + description "Use the launchd resource to manage system-wide services (daemons) and per-user services (agents) on the macOS platform." + introduced "12.8" + default_action :create allowed_actions :create, :create_if_missing, :delete, :enable, :disable, :restart diff --git a/lib/chef/resource/macos_userdefaults.rb b/lib/chef/resource/macos_userdefaults.rb new file mode 100644 index 0000000000..c0066c84b5 --- /dev/null +++ b/lib/chef/resource/macos_userdefaults.rb @@ -0,0 +1,126 @@ +# +# Copyright:: 2011-2018, Joshua Timberman +# Copyright:: 2018, 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. +# 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/resource" + +class Chef + class Resource + class MacosUserDefaults < Chef::Resource + # align with apple's marketing department + resource_name :macos_userdefaults + provides :mac_os_x_userdefaults + provides :macos_userdefaults + + introduced "14.0" + + description "Use the macos_userdefaults resource to manage the macOS user defaults"\ + " system. The properties to the resource are passed to the defaults command"\ + " and the parameters follow convention of the macOS command. See the defaults(1)"\ + " man page for details on how the tool works." + + property :domain, + String, + description: "The domain the defaults belong to.", + required: true + + property :global, + [true, false], + description: "Whether the domain is global.", + default: false + + property :key, + String, + description: "The preference key." + + property :value, + [Integer, Float, String, true, false, Hash, Array], + description: "The value of the key.", + coerce: proc { |v| coerce_booleans(v) }, + required: true + + property :type, + String, + description: "Value type of the preference key.", + default: "" + + property :user, + String, + description: "User for which to set the default." + + property :sudo, + [true, false], + description: "Set to true if the setting requires privileged access to modify.", + default: false, + desired_state: false + + property :is_set, + [true, false], + description: "", + default: false, + desired_state: false + + # coerce various ways of representing a boolean into either 0 (false) or 1 (true) + # which is what the defaults CLI expects. Why? Well defaults itself accepts a few + # different formats, but when you do a read command it all comes back as 1 or 0. + def coerce_booleans(val) + return 1 if [true, "TRUE", "1", "true", "YES", "yes"].include?(val) + return 0 if [false, "FALSE", "0", "false", "NO", "no"].include?(val) + val + end + + load_current_value do |desired| + drcmd = "defaults read '#{desired.domain}' " + drcmd << "'#{desired.key}' " if desired.key + shell_out_opts = {} + shell_out_opts[:user] = desired.user unless desired.user.nil? + vc = shell_out("#{drcmd} | grep -qx '#{desired.value}'", shell_out_opts) + is_set vc.exitstatus == 0 ? true : false + end + + action :write do + description "Write the setting to the specified domain" + + unless current_value.is_set + cmd = ["defaults write"] + cmd.unshift("sudo") if new_resource.sudo + + cmd << if new_resource.global + "NSGlobalDomain" + else + "'#{new_resource.domain}'" + end + + cmd << "'#{new_resource.key}'" if new_resource.key + value = new_resource.value + type = new_resource.type.empty? ? value_type(value) : new_resource.type + # creates a string of Key1 Value1 Key2 Value2... + value = value.map { |k, v| "\"#{k}\" \"#{v}\"" }.join(" ") if type == "dict" + if type == "array" + value = value.join("' '") + value = "'#{value}'" + end + cmd << "-#{type}" if type + cmd << value + + declare_resource(:execute, cmd.join(" ")) do + user new_resource.user unless new_resource.user.nil? + end + end + end + end + end +end diff --git a/lib/chef/resource/ohai_hint.rb b/lib/chef/resource/ohai_hint.rb new file mode 100644 index 0000000000..26b76806d7 --- /dev/null +++ b/lib/chef/resource/ohai_hint.rb @@ -0,0 +1,96 @@ +# +# Copyright:: Copyright 2011-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. +# + +class Chef + class Resource + class OhaiHint < Chef::Resource + resource_name :ohai_hint + provides :ohai_hint + + description "A resource to pass hint data to Ohai to aid in configuration detection." + introduced "14.0" + + property :hint_name, + String, + description: "The name of hints file if different from the resource name", + name_property: true + + property :content, + Hash, + description: "Values to include in the hint file" + + property :compile_time, + [TrueClass, FalseClass], + description: "Should the resource execute during the compile time phase", + default: true + + action :create do + description "Create an Ohai hint file" + + declare_resource(:directory, ::Ohai::Config.ohai.hints_path.first) do + action :create + recursive true + end + + declare_resource(:file, ohai_hint_file_path(new_resource.hint_name)) do + action :create + content format_content(new_resource.content) + end + end + + action :delete do + description "Delete an Ohai hint file" + + declare_resource(:file, ohai_hint_file_path(new_resource.hint_name)) do + action :delete + notifies :reload, ohai[reload ohai post hint removal] + end + + declare_resource(:ohai, "reload ohai post hint removal") do + action :nothing + end + end + + action_class do + # given a hint filename return the platform specific hint file path + # @param filename [String] the name of the hint file + # @return [String] absolute path to the file + def ohai_hint_file_path(filename) + path = ::File.join(::Ohai::Config.ohai.hints_path.first, filename) + path << ".json" unless path.end_with?(".json") + path + end + + # format content hash as JSON + # @param content [Hash] the content of the hint file + # @return [JSON] json representation of the content of an empty string if content was nil + def format_content(content) + return "" if content.nil? || content.empty? + JSON.pretty_generate(content) + end + end + + # this resource forces itself to run at compile_time + def after_created + return unless compile_time + Array(action).each do |action| + run_action(action) + end + end + end + end +end diff --git a/lib/chef/resource/powershell_package.rb b/lib/chef/resource/powershell_package.rb index 05c59acf73..829db5f4f8 100644 --- a/lib/chef/resource/powershell_package.rb +++ b/lib/chef/resource/powershell_package.rb @@ -41,6 +41,7 @@ class Chef property :version, [String, Array], coerce: proc { |x| [x].flatten } + property :source, [String] end end end diff --git a/lib/chef/resource/rhsm_errata.rb b/lib/chef/resource/rhsm_errata.rb new file mode 100644 index 0000000000..56779909f5 --- /dev/null +++ b/lib/chef/resource/rhsm_errata.rb @@ -0,0 +1,45 @@ +# +# Copyright:: 2015-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 "chef/resource" + +class Chef + class Resource + class RhsmErrata < Chef::Resource + resource_name :rhsm_errata + + description "A resource for installing packages associated with a given Red"\ + " Hat Subscription Manager Errata ID. This is helpful if packages"\ + " to mitigate a single vulnerability must be installed on your hosts." + introduced "14.0" + + property :errata_id, + String, + description: "An optional property for specifying the errata ID if not using the resource's name.", + name_property: true + + action :install do + description "Installs a package for a specific errata ID" + + execute "Install errata packages for #{new_resource.errata_id}" do + command "yum update --advisory #{new_resource.errata_id} -y" + action :run + end + end + end + end +end diff --git a/lib/chef/resource/rhsm_errata_level.rb b/lib/chef/resource/rhsm_errata_level.rb new file mode 100644 index 0000000000..3aa289ac2e --- /dev/null +++ b/lib/chef/resource/rhsm_errata_level.rb @@ -0,0 +1,53 @@ +# +# Copyright:: 2015-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 "chef/resource" + +class Chef + class Resource + class RhsmErrataLevel < Chef::Resource + resource_name :rhsm_errata_level + + description "A resource for installing all packages of a specified errata level"\ + " from the Red Hat Subscript Manager. For example, you can ensure"\ + " that all packages associated with errata marked at a 'Critical'"\ + " security level are installed." + introduced "14.0" + + property :errata_level, + String, + coerce: proc { |x| x.downcase }, + equal_to: %w{critical moderate important low}, + description: "The errata level of packages to install.", + name_property: true + + action :install do + descripton "Install all packages of the specified errata level" + + yum_package "yum-plugin-security" do + action :install + only_if { node["platform_version"].to_i == 6 } + end + + execute "Install any #{new_resource.errata_level} errata" do + command "yum update --sec-severity=#{new_resource.errata_level.capitalize} -y" + action :run + end + end + end + end +end diff --git a/lib/chef/resource/rhsm_register.rb b/lib/chef/resource/rhsm_register.rb new file mode 100644 index 0000000000..47fe67d1cf --- /dev/null +++ b/lib/chef/resource/rhsm_register.rb @@ -0,0 +1,170 @@ +# +# Copyright:: 2015-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 "chef/resource" +require "shellwords" + +class Chef + class Resource + class RhsmRegister < Chef::Resource + resource_name :rhsm_register + + description "A resource for registering a node with the Red Hat Subscription Manager"\ + " or a local Red Hat Satellite server." + introduced "14.0" + + property :activation_key, + [String, Array], + coerce: proc { |x| Array(x) }, + description: "A String or array of the activation keys to use when registering. You must also specify the organization property if using activation_key." + + property :satellite_host, + String, + description: "The FQDN of the Satellite host to register with. If not specified, the host will be registered with Red Hat's public RHSM service." + + property :organization, + String, + description: "The organization to use when registering, required when using an activation key" + + property :environment, + String, + description: "The environment to use when registering, required when using username and password" + + property :username, + String, + description: "The username to use when registering. Not applicable if using an activation key. If specified, password and environment are also required." + + property :password, + String, + description: "The password to use when registering. Not applicable if using an activation key. If specified, username and environment are also required." + + property :auto_attach, + [TrueClass, FalseClass], + description: "If true, RHSM will attempt to automatically attach the host to applicable subscriptions. It is generally better to use an activation key with the subscriptions pre-defined.", + default: false + + property :install_katello_agent, + [TrueClass, FalseClass], + description: "If true, the 'katello-agent' RPM will be installed.", + default: true + + property :force, + [TrueClass, FalseClass], + description: "If true, the system will be registered even if it is already registered. Normally, any register operations will fail if the machine is has already registered.", + default: false + + action :register do + description "Register the node with RHSM" + + package "subscription-manager" + + unless new_resource.satellite_host.nil? || registered_with_rhsm? + remote_file "#{Chef::Config[:file_cache_path]}/katello-package.rpm" do + source "http://#{new_resource.satellite_host}/pub/katello-ca-consumer-latest.noarch.rpm" + action :create + notifies :install, "yum_package[katello-ca-consumer-latest]", :immediately + not_if { katello_cert_rpm_installed? } + end + + yum_package "katello-ca-consumer-latest" do + options "--nogpgcheck" + source "#{Chef::Config[:file_cache_path]}/katello-package.rpm" + action :nothing + end + + file "#{Chef::Config[:file_cache_path]}/katello-package.rpm" do + action :delete + end + end + + execute "Register to RHSM" do + sensitive new_resource.sensitive + command register_command + action :run + not_if { registered_with_rhsm? } + end + + yum_package "katello-agent" do + action :install + only_if { new_resource.install_katello_agent && !new_resource.satellite_host.nil? } + end + end + + action :unregister do + description "Unregister the node from RHSM" + + execute "Unregister from RHSM" do + command "subscription-manager unregister" + action :run + only_if { registered_with_rhsm? } + notifies :run, "execute[Clean RHSM Config]", :immediately + end + + execute "Clean RHSM Config" do + command "subscription-manager clean" + action :nothing + end + end + + action_class do + def registered_with_rhsm? + cmd = Mixlib::ShellOut.new("subscription-manager status", env: { LANG: "en_US" }) + cmd.run_command + !cmd.stdout.match(/Overall Status: Unknown/) + end + + def katello_cert_rpm_installed? + cmd = Mixlib::ShellOut.new("rpm -qa | grep katello-ca-consumer") + cmd.run_command + !cmd.stdout.match(/katello-ca-consumer/).nil? + end + + def register_command + command = %w{subscription-manager register} + + unless new_resource.activation_key.empty? + raise "Unable to register - you must specify organization when using activation keys" if new_resource.organization.nil? + + command << new_resource.activation_key.map { |key| "--activationkey=#{Shellwords.shellescape(key)}" } + command << "--org=#{Shellwords.shellescape(new_resource.organization)}" + command << "--force" if new_resource.force + + return command.join(" ") + end + + if new_resource.username && new_resource.password + raise "Unable to register - you must specify environment when using username/password" if new_resource.environment.nil? && using_satellite_host? + + command << "--username=#{Shellwords.shellescape(new_resource.username)}" + command << "--password=#{Shellwords.shellescape(new_resource.password)}" + command << "--environment=#{Shellwords.shellescape(new_resource.environment)}" if using_satellite_host? + command << "--auto-attach" if new_resource.auto_attach + command << "--force" if new_resource.force + + return command.join(" ") + end + + raise "Unable to create register command - you must specify activation_key or username/password" + end + + def using_satellite_host? + !new_resource.satellite_host.nil? + end + end + end + end +end diff --git a/lib/chef/resource/rhsm_repo.rb b/lib/chef/resource/rhsm_repo.rb new file mode 100644 index 0000000000..aef4dd43d6 --- /dev/null +++ b/lib/chef/resource/rhsm_repo.rb @@ -0,0 +1,63 @@ +# +# Copyright:: 2015-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 "chef/resource" + +class Chef + class Resource + class RhsmRepo < Chef::Resource + resource_name :rhsm_repo + + description "A resource for enabling and disabling Red Hat Subscription Manager"\ + " repositories that are made available via attached subscriptions." + introduced "14.0" + + property :repo_name, + String, + description: "An optional property for specifying the repository name if not using the resource's name.", + name_property: true + + action :enable do + description "Enable a RHSM repository" + + execute "Enable repository #{repo_name}" do + command "subscription-manager repos --enable=#{repo_name}" + action :run + not_if { repo_enabled?(repo_name) } + end + end + + action :disable do + description "Disable a RHSM repository" + + execute "Enable repository #{repo_name}" do + command "subscription-manager repos --disable=#{repo_name}" + action :run + only_if { repo_enabled?(repo_name) } + end + end + + action_class do + def repo_enabled?(repo) + cmd = Mixlib::ShellOut.new("subscription-manager repos --list-enabled", env: { LANG: "en_US" }) + cmd.run_command + !cmd.stdout.match(/Repo ID:\s+#{repo}$/).nil? + end + end + end + end +end diff --git a/lib/chef/resource/rhsm_subscription.rb b/lib/chef/resource/rhsm_subscription.rb new file mode 100644 index 0000000000..41dd398cd5 --- /dev/null +++ b/lib/chef/resource/rhsm_subscription.rb @@ -0,0 +1,96 @@ +# +# Copyright:: 2015-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 "chef/resource" + +class Chef + class Resource + class RhsmSubscription < Chef::Resource + resource_name :rhsm_subscription + + description "A resource for adding additional Redhat Subscription Manager subscriptions"\ + " to your host. This can be used when a host's activation_key"\ + " does not attach all necessary subscriptions to your host." + introduced "14.0" + + property :pool_id, + String, + description: "An optional property for specifying the Pool ID if not using the resource's name.", + name_property: true + + action :attach do + description "Attach the node to a subscription pool" + + execute "Attach subscription pool #{new_resource.pool_id}" do + command "subscription-manager attach --pool=#{new_resource.pool_id}" + action :run + not_if { subscription_attached?(new_resource.pool_id) } + end + end + + action :remove do + description "Remove the node from a subscription pool" + + execute "Remove subscription pool #{new_resource.pool_id}" do + command "subscription-manager remove --serial=#{pool_serial(new_resource.pool_id)}" + action :run + only_if { subscription_attached?(new_resource.pool_id) } + end + end + + action_class do + def subscription_attached?(subscription) + cmd = Mixlib::ShellOut.new("subscription-manager list --consumed | grep #{subscription}", env: { LANG: "en_US" }) + cmd.run_command + !cmd.stdout.match(/Pool ID:\s+#{subscription}$/).nil? + end + + def serials_by_pool + serials = {} + pool = nil + serial = nil + + cmd = Mixlib::ShellOut.new("subscription-manager list --consumed", env: { LANG: "en_US" }) + cmd.run_command + cmd.stdout.lines.each do |line| + line.strip! + key, value = line.split(/:\s+/, 2) + next unless ["Pool ID", "Serial"].include?(key) + + if key == "Pool ID" + pool = value + elsif key == "Serial" + serial = value + end + + next unless pool && serial + + serials[pool] = serial + pool = nil + serial = nil + end + + serials + end + + def pool_serial(pool_id) + serials_by_pool[pool_id] + end + end + end + end +end diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb index b580a01c29..c10bf98b2f 100644 --- a/lib/chef/resources.rb +++ b/lib/chef/resources.rb @@ -41,6 +41,7 @@ require "chef/resource/gem_package" require "chef/resource/git" require "chef/resource/group" require "chef/resource/http_request" +require "chef/resource/hostname" require "chef/resource/homebrew_package" require "chef/resource/ifconfig" require "chef/resource/ksh" @@ -48,9 +49,11 @@ require "chef/resource/launchd" require "chef/resource/link" require "chef/resource/log" require "chef/resource/macports_package" +require "chef/resource/macos_userdefaults" require "chef/resource/mdadm" require "chef/resource/mount" require "chef/resource/ohai" +require "chef/resource/ohai_hint" require "chef/resource/openbsd_package" require "chef/resource/openssl_dhparam" require "chef/resource/openssl_rsa_private_key" @@ -67,6 +70,11 @@ require "chef/resource/reboot" require "chef/resource/registry_key" require "chef/resource/remote_directory" require "chef/resource/remote_file" +require "chef/resource/rhsm_errata_level" +require "chef/resource/rhsm_errata" +require "chef/resource/rhsm_register" +require "chef/resource/rhsm_repo" +require "chef/resource/rhsm_subscription" require "chef/resource/rpm_package" require "chef/resource/solaris_package" require "chef/resource/route" diff --git a/lib/chef/version.rb b/lib/chef/version.rb index 7aaaf7602a..8d8e5151c5 100644 --- a/lib/chef/version.rb +++ b/lib/chef/version.rb @@ -23,7 +23,7 @@ require "chef/version_string" class Chef CHEF_ROOT = File.expand_path("../..", __FILE__) - VERSION = Chef::VersionString.new("14.0.60") + VERSION = Chef::VersionString.new("14.0.71") end # diff --git a/omnibus_overrides.rb b/omnibus_overrides.rb index 8da7dc9940..e40a322775 100644 --- a/omnibus_overrides.rb +++ b/omnibus_overrides.rb @@ -8,7 +8,7 @@ override "libffi", version: "3.2.1" override "libiconv", version: "1.15" override "liblzma", version: "5.2.3" override "libtool", version: "2.4.2" -override "libxml2", version: "2.9.5" +override "libxml2", version: "2.9.7" override "libxslt", version: "1.1.30" override "libyaml", version: "0.1.7" override "makedepend", version: "1.0.5" diff --git a/spec/unit/knife/configure_spec.rb b/spec/unit/knife/configure_spec.rb index f1d3bd0745..27bb0d9a3f 100644 --- a/spec/unit/knife/configure_spec.rb +++ b/spec/unit/knife/configure_spec.rb @@ -26,8 +26,7 @@ describe Chef::Knife::Configure do let(:ohai) do o = {} - allow(o).to receive(:require_plugin) - allow(o).to receive(:load_plugins) + allow(o).to receive(:all_plugins).with(%w{ os hostname fqdn }) o[:fqdn] = fqdn o end diff --git a/spec/unit/provider/package/powershell_spec.rb b/spec/unit/provider/package/powershell_spec.rb index 4e86b0fe83..9bebfa9194 100644 --- a/spec/unit/provider/package/powershell_spec.rb +++ b/spec/unit/provider/package/powershell_spec.rb @@ -22,6 +22,7 @@ require "chef/mixin/powershell_out" describe Chef::Provider::Package::Powershell do include Chef::Mixin::PowershellOut let(:timeout) { 900 } + let(:source) { nil } let(:new_resource) { Chef::Resource::PowershellPackage.new("windows_test_pkg") } @@ -92,6 +93,20 @@ describe Chef::Provider::Package::Powershell do double("powershell_out", :stdout => "5") end + let(:generated_command) { "( Get-Package posh-git -Force -ForceBootstrap ).Version" } + let(:generated_get_cmdlet) { "( Get-Package xNetworking -Force -ForceBootstrap ).Version" } + let(:generated_get_cmdlet_with_version) { "( Get-Package xNetworking -Force -ForceBootstrap -RequiredVersion 1.0.0.0 ).Version" } + let(:generated_find_cmdlet) { "( Find-Package xNetworking -Force -ForceBootstrap ).Version" } + let(:generated_find_cmdlet_with_version) { "( Find-Package xNetworking -Force -ForceBootstrap -RequiredVersion 1.0.0.0 ).Version" } + let(:generated_find_cmdlet_with_source) { "( Find-Package xNetworking -Force -ForceBootstrap -Source MyGallery ).Version" } + let(:generated_find_cmdlet_with_source_and_version) { "( Find-Package xNetworking -Force -ForceBootstrap -RequiredVersion 1.0.0.0 -Source MyGallery ).Version" } + let(:generated_install_cmdlet) { "( Install-Package xNetworking -Force -ForceBootstrap ).Version" } + let(:generated_install_cmdlet_with_version) { "( Install-Package xNetworking -Force -ForceBootstrap -RequiredVersion 1.0.0.0 ).Version" } + let(:generated_install_cmdlet_with_source) { "( Install-Package xNetworking -Force -ForceBootstrap -Source MyGallery ).Version" } + let(:generated_install_cmdlet_with_source_and_version) { "( Install-Package xNetworking -Force -ForceBootstrap -RequiredVersion 1.0.0.0 -Source MyGallery ).Version" } + let(:generated_uninstall_cmdlet) { "( Uninstall-Package xNetworking -Force -ForceBootstrap ).Version" } + let(:generated_uninstall_cmdlet_with_version) { "( Uninstall-Package xNetworking -Force -ForceBootstrap -RequiredVersion 1.0.0.0 ).Version" } + describe "#initialize" do it "should return the correct class" do expect(provider).to be_kind_of(Chef::Provider::Package::Powershell) @@ -101,67 +116,75 @@ describe Chef::Provider::Package::Powershell do describe "#candidate_version" do it "should set the candidate_version to the latest version when not pinning" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) new_resource.package_name(["xNetworking"]) new_resource.version(nil) expect(provider.candidate_version).to eql(["2.12.0.0"]) end + it "should use the candidate_version from the correct source" do + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap -Source MyGallery ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + new_resource.package_name(["xNetworking"]) + new_resource.version(nil) + new_resource.source("MyGallery") + expect(provider.candidate_version).to eql(["2.12.0.0"]) + end + it "should set the candidate_version to the latest version when not pinning and package name is space seperated" do - allow(provider).to receive(:powershell_out).with("(Find-Package '7-Zip 16.02 (x64)' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_7zip_available) + allow(provider).to receive(:powershell_out).with("( Find-Package '7-Zip 16.02 (x64)' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_7zip_available) new_resource.package_name(["7-Zip 16.02 (x64)"]) new_resource.version(nil) expect(provider.candidate_version).to eql(["16.02"]) end it "should set the candidate_version to pinned version if available" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.0.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available_2_0_0_0) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.0.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available_2_0_0_0) new_resource.package_name(["xCertificate"]) new_resource.version(["2.0.0.0"]) expect(provider.candidate_version).to eql(["2.0.0.0"]) end it "should set the candidate_version to nil if there is no candidate" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) new_resource.package_name(["xCertificate"]) expect(provider.candidate_version).to eql([nil]) end it "should set the candidate_version correctly when there are two packages to install" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) new_resource.package_name(%w{xCertificate xNetworking}) new_resource.version(nil) expect(provider.candidate_version).to eql(["2.1.0.0", "2.12.0.0"]) end it "should set the candidate_version correctly when only the first is installable" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) new_resource.package_name(%w{xCertificate xNetworking}) new_resource.version(nil) expect(provider.candidate_version).to eql(["2.1.0.0", nil]) end it "should set the candidate_version correctly when only the last is installable" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) new_resource.package_name(%w{xCertificate xNetworking}) new_resource.version(nil) expect(provider.candidate_version).to eql([nil, "2.12.0.0"]) end it "should set the candidate_version correctly when neither are is installable and version is passed as nil array" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) new_resource.package_name(%w{xNetworking xCertificate}) new_resource.version([nil, nil]) expect(provider.candidate_version).to eql([nil, nil]) end it "should set the candidate_version correctly when neither are is installable and version is not passed" do - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) new_resource.package_name(%w{xNetworking xCertificate}) new_resource.version(nil) expect(provider.candidate_version).to eql([nil, nil]) @@ -169,15 +192,114 @@ describe Chef::Provider::Package::Powershell do end + describe "#build_powershell_command" do + it "can build a valid command from a single string" do + expect(provider.build_powershell_command("Get-Package posh-git")).to eql(generated_command) + end + + it "can build a valid command from an array" do + expect(provider.build_powershell_command(["Get-Package", "posh-git"])).to eql(generated_command) + end + + context "when source is nil" do + it "build get commands correctly" do + expect(provider.build_powershell_command("Get-Package xNetworking")).to eql(generated_get_cmdlet) + end + + it "build get commands correctly when a version is passed" do + expect(provider.build_powershell_command("Get-Package xNetworking", "1.0.0.0")).to eql(generated_get_cmdlet_with_version) + end + + it "builds find commands correctly" do + expect(provider.build_powershell_command("Find-Package xNetworking")).to eql(generated_find_cmdlet) + end + + it "builds find commands correctly when a version is passed" do + expect(provider.build_powershell_command("Find-Package xNetworking", "1.0.0.0")).to eql(generated_find_cmdlet_with_version) + end + + it "build install commands correctly" do + expect(provider.build_powershell_command("Install-Package xNetworking")).to eql(generated_install_cmdlet) + end + + it "build install commands correctly when a version is passed" do + expect(provider.build_powershell_command("Install-Package xNetworking", "1.0.0.0")).to eql(generated_install_cmdlet_with_version) + end + + it "build install commands correctly" do + expect(provider.build_powershell_command("Uninstall-Package xNetworking")).to eql(generated_uninstall_cmdlet) + end + + it "build install commands correctly when a version is passed" do + expect(provider.build_powershell_command("Uninstall-Package xNetworking", "1.0.0.0")).to eql(generated_uninstall_cmdlet_with_version) + end + end + + context "when source is set" do + it "build get commands correctly" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Get-Package xNetworking")).to eql(generated_get_cmdlet) + end + + it "build get commands correctly when a version is passed" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Get-Package xNetworking", "1.0.0.0")).to eql(generated_get_cmdlet_with_version) + end + + it "builds find commands correctly" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Find-Package xNetworking")).to eql(generated_find_cmdlet_with_source) + end + + it "builds find commands correctly when a version is passed" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Find-Package xNetworking", "1.0.0.0")).to eql(generated_find_cmdlet_with_source_and_version) + end + + it "build install commands correctly" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Install-Package xNetworking")).to eql(generated_install_cmdlet_with_source) + end + + it "build install commands correctly when a version is passed" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Install-Package xNetworking", "1.0.0.0")).to eql(generated_install_cmdlet_with_source_and_version) + end + + it "build install commands correctly" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Uninstall-Package xNetworking")).to eql(generated_uninstall_cmdlet) + end + + it "build install commands correctly when a version is passed" do + new_resource.source("MyGallery") + expect(provider.build_powershell_command("Uninstall-Package xNetworking", "1.0.0.0")).to eql(generated_uninstall_cmdlet_with_version) + end + end + end + describe "#action_install" do it "should install a single package" do provider.load_current_resource new_resource.package_name(["xCertificate"]) new_resource.version(nil) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }) + provider.run_action(:install) + expect(new_resource).to be_updated_by_last_action + end + + it "should install a single package from a custom source" do + provider.load_current_resource + new_resource.package_name(["xCertificate"]) + new_resource.version(nil) + new_resource.source("MyGallery") + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap -Source MyGallery ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) - expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 -Source MyGallery ).Version", { :timeout => new_resource.timeout }) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -186,10 +308,10 @@ describe Chef::Provider::Package::Powershell do provider.load_current_resource new_resource.package_name(["7-Zip 16.02 (x64)"]) new_resource.version(nil) - allow(provider).to receive(:powershell_out).with("(Find-Package '7-Zip 16.02 (x64)' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_7zip_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name '7-Zip 16.02 (x64)' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_7zip_not_installed) + allow(provider).to receive(:powershell_out).with("( Find-Package '7-Zip 16.02 (x64)' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_7zip_available) + allow(provider).to receive(:powershell_out).with("( Get-Package '7-Zip 16.02 (x64)' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_7zip_not_installed) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) - expect(provider).to receive(:powershell_out).with("Install-Package '7-Zip 16.02 (x64)' -Force -ForceBootstrap -RequiredVersion 16.02", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package '7-Zip 16.02 (x64)' -Force -ForceBootstrap -RequiredVersion 16.02 ).Version", { :timeout => new_resource.timeout }) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -201,10 +323,10 @@ describe Chef::Provider::Package::Powershell do provider.load_current_resource new_resource.package_name(["xCertificate"]) new_resource.version(nil) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) - expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -213,8 +335,8 @@ describe Chef::Provider::Package::Powershell do it "should not install packages that are up-to-date" do new_resource.package_name(["xCertificate"]) new_resource.version(nil) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) provider.load_current_resource expect(provider).not_to receive(:install_package) @@ -225,8 +347,8 @@ describe Chef::Provider::Package::Powershell do it "should not install packages that are up-to-date" do new_resource.package_name(["xNetworking"]) new_resource.version(["2.11.0.0"]) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available_2_11_0_0) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.11.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.11.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available_2_11_0_0) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) provider.load_current_resource expect(provider).not_to receive(:install_package) @@ -239,13 +361,13 @@ describe Chef::Provider::Package::Powershell do # new_version.resource[0] new_resource.package_name(%w{xCertificate xNetworking}) new_resource.version([nil, "2.11.0.0"]) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available_2_11_0_0) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -RequiredVersion 2.11.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.11.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available_2_11_0_0) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.11.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) - expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout }) - expect(provider).to receive(:powershell_out).with("Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.11.0.0", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.11.0.0 ).Version", { :timeout => new_resource.timeout }) provider.load_current_resource provider.run_action(:install) expect(new_resource).to be_updated_by_last_action @@ -254,13 +376,13 @@ describe Chef::Provider::Package::Powershell do it "should split up commands when given two packages, one with a version pin" do new_resource.package_name(%w{xCertificate xNetworking}) new_resource.version(["2.1.0.0", nil]) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) - expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout }) - expect(provider).to receive(:powershell_out).with("Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.12.0.0", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.12.0.0 ).Version", { :timeout => new_resource.timeout }) provider.load_current_resource provider.run_action(:install) @@ -270,13 +392,29 @@ describe Chef::Provider::Package::Powershell do it "should do multipackage installs when given two packages without constraints" do new_resource.package_name(%w{xCertificate xNetworking}) new_resource.version(nil) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.12.0.0 ).Version", { :timeout => new_resource.timeout }) + provider.load_current_resource + provider.run_action(:install) + expect(new_resource).to be_updated_by_last_action + end + + it "should do multipackage installs from a custom source when given two packages without constraints" do + new_resource.package_name(%w{xCertificate xNetworking}) + new_resource.version(nil) + new_resource.source("MyGallery") + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap -Source MyGallery ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap -Source MyGallery ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) - expect(provider).to receive(:powershell_out).with("Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout }) - expect(provider).to receive(:powershell_out).with("Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.12.0.0", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 -Source MyGallery ).Version", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Install-Package 'xNetworking' -Force -ForceBootstrap -RequiredVersion 2.12.0.0 -Source MyGallery ).Version", { :timeout => new_resource.timeout }) provider.load_current_resource provider.run_action(:install) expect(new_resource).to be_updated_by_last_action @@ -288,21 +426,34 @@ describe Chef::Provider::Package::Powershell do provider.load_current_resource new_resource.package_name(["xCertificate"]) new_resource.version(["2.1.0.0"]) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) expect(provider).not_to receive(:remove_package) provider.run_action(:remove) expect(new_resource).not_to be_updated_by_last_action end + it "does not pass the source parameter to get or uninstall cmdlets" do + new_resource.package_name(["xCertificate"]) + new_resource.version(["2.1.0.0"]) + new_resource.source("MyGallery") + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 -Source MyGallery).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) + provider.load_current_resource + expect(provider).to receive(:powershell_out).with("( Uninstall-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }) + provider.run_action(:remove) + expect(new_resource).to be_updated_by_last_action + end + it "does nothing when all the packages are already removed" do new_resource.package_name(%w{xCertificate xNetworking}) new_resource.version(nil) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xNetworking' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xNetworking' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xnetworking_not_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) provider.load_current_resource expect(provider).not_to receive(:remove_package) @@ -313,11 +464,11 @@ describe Chef::Provider::Package::Powershell do it "removes a package when version is specified" do new_resource.package_name(["xCertificate"]) new_resource.version(["2.1.0.0"]) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -RequiredVersion 2.1.0.0 -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) provider.load_current_resource - expect(provider).to receive(:powershell_out).with("Uninstall-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0", { :timeout => new_resource.timeout }) + expect(provider).to receive(:powershell_out).with("( Uninstall-Package 'xCertificate' -Force -ForceBootstrap -RequiredVersion 2.1.0.0 ).Version", { :timeout => new_resource.timeout }) provider.run_action(:remove) expect(new_resource).to be_updated_by_last_action end @@ -325,11 +476,11 @@ describe Chef::Provider::Package::Powershell do it "removes a package when version is not specified" do new_resource.package_name(["xCertificate"]) new_resource.version(nil) - allow(provider).to receive(:powershell_out).with("(Find-Package 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) - allow(provider).to receive(:powershell_out).with("(Get-Package -Name 'xCertificate' -ForceBootstrap -Force).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Find-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) + allow(provider).to receive(:powershell_out).with("( Get-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_available) allow(provider).to receive(:powershell_out).with("$PSVersionTable.PSVersion.Major").and_return(powershell_installed_version) provider.load_current_resource - expect(provider).to receive(:powershell_out).with("(Uninstall-Package 'xCertificate' -Force -ForceBootstrap).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) + expect(provider).to receive(:powershell_out).with("( Uninstall-Package 'xCertificate' -Force -ForceBootstrap ).Version", { :timeout => new_resource.timeout }).and_return(package_xcertificate_not_available) provider.run_action(:remove) expect(new_resource).to be_updated_by_last_action end diff --git a/spec/unit/resource/hostname_spec.rb b/spec/unit/resource/hostname_spec.rb new file mode 100644 index 0000000000..33f944dbc9 --- /dev/null +++ b/spec/unit/resource/hostname_spec.rb @@ -0,0 +1,43 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::Hostname do + + let(:resource) { Chef::Resource::Hostname.new("foo") } + + it "has a resource name of :hostname" do + expect(resource.resource_name).to eql(:hostname) + end + + it "has a default action of set" do + expect(resource.action).to eql([:set]) + end + + it "runs at compile_time by default" do + expect(resource.compile_time).to eql(true) + end + + it "reboots windows nodes by default" do + expect(resource.windows_reboot).to eql(true) + end + + it "the hostname property is the name property" do + expect(resource.hostname).to eql("foo") + end +end diff --git a/spec/unit/resource/macos_user_defaults_spec.rb b/spec/unit/resource/macos_user_defaults_spec.rb new file mode 100644 index 0000000000..6ef82853cc --- /dev/null +++ b/spec/unit/resource/macos_user_defaults_spec.rb @@ -0,0 +1,45 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::MacosUserDefaults do + + let(:resource) { Chef::Resource::MacosUserDefaults.new("foo") } + + it "has a resource name of :macos_userdefaults" do + expect(resource.resource_name).to eql(:macos_userdefaults) + end + + it "has a default action of install" do + expect(resource.action).to eql([:write]) + end + + [true, "TRUE", "1", "true", "YES", "yes"].each do |val| + it "coerces value property from #{val} to 1" do + resource.value val + expect(resource.value).to eql(1) + end + end + + [false, "FALSE", "0", "false", "NO", "no"].each do |val| + it "coerces value property from #{val} to 0" do + resource.value val + expect(resource.value).to eql(0) + end + end +end diff --git a/spec/unit/resource/ohai_hint_spec.rb b/spec/unit/resource/ohai_hint_spec.rb new file mode 100644 index 0000000000..1a4f6637fa --- /dev/null +++ b/spec/unit/resource/ohai_hint_spec.rb @@ -0,0 +1,43 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::OhaiHint do + + let(:resource) { Chef::Resource::OhaiHint.new("foo") } + + it "has a resource name of :ohai_hint" do + expect(resource.resource_name).to eql(:ohai_hint) + end + + it "has a default action of create" do + expect(resource.action).to eql([:create]) + end + + it "supports the :nothing, :create and :delete actions" do + expect(resource.allowed_actions).to include(:nothing, :create, :delete) + end + + it "runs at compile_time by default" do + expect(resource.compile_time).to eql(true) + end + + it "the hint_name property is the name property" do + expect(resource.hint_name).to eql("foo") + end +end diff --git a/spec/unit/resource/powershell_package_spec.rb b/spec/unit/resource/powershell_package_spec.rb index 701014bd95..a448d58d5a 100644 --- a/spec/unit/resource/powershell_package_spec.rb +++ b/spec/unit/resource/powershell_package_spec.rb @@ -63,4 +63,13 @@ describe Chef::Resource::PowershellPackage do resource.version(["1.2.3", "4.5.6"]) expect(resource.version).to eql(["1.2.3", "4.5.6"]) end + + it "the default source is nil" do + expect(resource.source).to eql(nil) + end + + it "the source setter accepts strings" do + resource.source("MyGallery") + expect(resource.source).to eql("MyGallery") + end end diff --git a/spec/unit/resource/rhsm_errata_level_spec.rb b/spec/unit/resource/rhsm_errata_level_spec.rb new file mode 100644 index 0000000000..3284107e75 --- /dev/null +++ b/spec/unit/resource/rhsm_errata_level_spec.rb @@ -0,0 +1,46 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::RhsmErrataLevel do + + let(:resource) { Chef::Resource::RhsmErrataLevel.new("moderate") } + + it "has a resource name of :rhsm_errata_level" do + expect(resource.resource_name).to eql(:rhsm_errata_level) + end + + it "has a default action of install" do + expect(resource.action).to eql([:install]) + end + + it "the errata_level property is the name property" do + expect(resource.errata_level).to eql("moderate") + end + + it "coerces the errata_level to be lowercase" do + resource.errata_level "Important" + expect(resource.errata_level).to eql("important") + end + + it "raises an exception if invalid errata_level is passed" do + expect do + resource.errata_level "FOO" + end.to raise_error(Chef::Exceptions::ValidationFailed) + end +end diff --git a/spec/unit/resource/rhsm_errata_spec.rb b/spec/unit/resource/rhsm_errata_spec.rb new file mode 100644 index 0000000000..8da7269ca8 --- /dev/null +++ b/spec/unit/resource/rhsm_errata_spec.rb @@ -0,0 +1,35 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::RhsmErrata do + + let(:resource) { Chef::Resource::RhsmErrata.new("foo") } + + it "has a resource name of :rhsm_errata" do + expect(resource.resource_name).to eql(:rhsm_errata) + end + + it "has a default action of install" do + expect(resource.action).to eql([:install]) + end + + it "the errata_id property is the name property" do + expect(resource.errata_id).to eql("foo") + end +end diff --git a/spec/unit/resource/rhsm_register_spec.rb b/spec/unit/resource/rhsm_register_spec.rb new file mode 100644 index 0000000000..2e360b5708 --- /dev/null +++ b/spec/unit/resource/rhsm_register_spec.rb @@ -0,0 +1,199 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::RhsmRegister do + + let(:resource) { Chef::Resource::RhsmRegister.new("foo") } + let(:provider) { resource.provider_for_action(:register) } + + it "has a resource name of :rhsm_register" do + expect(resource.resource_name).to eql(:rhsm_register) + end + + it "has a default action of register" do + expect(resource.action).to eql([:register]) + end + + it "coerces activation_key to an array" do + resource.activation_key "foo" + expect(resource.activation_key).to eql(["foo"]) + end + + describe "#katello_cert_rpm_installed?" do + let(:cmd) { double("cmd") } + + before do + allow(Mixlib::ShellOut).to receive(:new).and_return(cmd) + allow(cmd).to receive(:run_command) + end + + context "when the output contains katello-ca-consumer" do + it "returns true" do + allow(cmd).to receive(:stdout).and_return("katello-ca-consumer-somehostname-1.0-1") + expect(provider.katello_cert_rpm_installed?).to eq(true) + end + end + + context "when the output does not contain katello-ca-consumer" do + it "returns false" do + allow(cmd).to receive(:stdout).and_return("katello-agent-but-not-the-ca") + expect(provider.katello_cert_rpm_installed?).to eq(false) + end + end + end + + describe "#register_command" do + before do + allow(provider).to receive(:activation_key).and_return([]) + allow(provider).to receive(:auto_attach) + end + + context "when activation keys exist" do + before do + allow(resource).to receive(:activation_key).and_return(%w{key1 key2}) + end + + context "when no org exists" do + it "raises an exception" do + allow(resource).to receive(:organization).and_return(nil) + expect { provider.register_command }.to raise_error(RuntimeError) + end + end + + context "when an org exists" do + it "returns a command containing the keys and org" do + allow(resource).to receive(:organization).and_return("myorg") + + expect(provider.register_command).to match("--activationkey=key1 --activationkey=key2 --org=myorg") + end + end + + context "when auto_attach is true" do + it "does not return a command with --auto-attach since it is not supported with activation keys" do + allow(resource).to receive(:organization).and_return("myorg") + allow(resource).to receive(:auto_attach).and_return(true) + + expect(provider.register_command).not_to match("--auto-attach") + end + end + end + + context "when username and password exist" do + before do + allow(resource).to receive(:username).and_return("myuser") + allow(resource).to receive(:password).and_return("mypass") + allow(resource).to receive(:environment) + allow(resource).to receive(:using_satellite_host?) + allow(resource).to receive(:activation_key).and_return([]) + end + + context "when auto_attach is true" do + it "returns a command containing --auto-attach" do + allow(resource).to receive(:auto_attach).and_return(true) + + expect(provider.register_command).to match("--auto-attach") + end + end + + context "when auto_attach is false" do + it "returns a command that does not contain --auto-attach" do + allow(resource).to receive(:auto_attach).and_return(false) + + expect(provider.register_command).not_to match("--auto-attach") + end + end + + context "when auto_attach is nil" do + it "returns a command that does not contain --auto-attach" do + allow(resource).to receive(:auto_attach).and_return(nil) + + expect(provider.register_command).not_to match("--auto-attach") + end + end + + context "when environment does not exist" do + context "when registering to a satellite server" do + it "raises an exception" do + allow(provider).to receive(:using_satellite_host?).and_return(true) + allow(resource).to receive(:environment).and_return(nil) + expect { provider.register_command }.to raise_error(RuntimeError) + end + end + + context "when registering to RHSM proper" do + before do + allow(provider).to receive(:using_satellite_host?).and_return(false) + allow(resource).to receive(:environment).and_return(nil) + end + + it "does not raise an exception" do + expect { provider.register_command }.not_to raise_error + end + + it "returns a command containing the username and password and no environment" do + allow(resource).to receive(:environment).and_return("myenv") + expect(provider.register_command).to match("--username=myuser --password=mypass") + expect(provider.register_command).not_to match("--environment") + end + end + end + + context "when an environment exists" do + it "returns a command containing the username, password, and environment" do + allow(provider).to receive(:using_satellite_host?).and_return(true) + allow(resource).to receive(:environment).and_return("myenv") + expect(provider.register_command).to match("--username=myuser --password=mypass --environment=myenv") + end + end + end + + context "when no activation keys, username, or password exist" do + it "raises an exception" do + allow(resource).to receive(:activation_key).and_return([]) + allow(resource).to receive(:username).and_return(nil) + allow(resource).to receive(:password).and_return(nil) + + expect { provider.register_command }.to raise_error(RuntimeError) + end + end + end + + describe "#registered_with_rhsm?" do + let(:cmd) { double("cmd") } + + before do + allow(Mixlib::ShellOut).to receive(:new).and_return(cmd) + allow(cmd).to receive(:run_command) + end + + context "when the status is Unknown" do + it "returns false" do + allow(cmd).to receive(:stdout).and_return("Overall Status: Unknown") + expect(provider.registered_with_rhsm?).to eq(false) + end + end + + context "when the status is anything else" do + it "returns true" do + allow(cmd).to receive(:stdout).and_return("Overall Status: Insufficient") + expect(provider.registered_with_rhsm?).to eq(true) + end + end + end +end diff --git a/spec/unit/resource/rhsm_repo_spec.rb b/spec/unit/resource/rhsm_repo_spec.rb new file mode 100644 index 0000000000..97606a03c8 --- /dev/null +++ b/spec/unit/resource/rhsm_repo_spec.rb @@ -0,0 +1,59 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::RhsmRepo do + + let(:resource) { Chef::Resource::RhsmRepo.new("foo") } + let(:provider) { resource.provider_for_action(:enable) } + + it "has a resource name of :rhsm_repo" do + expect(resource.resource_name).to eql(:rhsm_repo) + end + + it "has a default action of enable" do + expect(resource.action).to eql([:enable]) + end + + it "the repo_name property is the name property" do + expect(resource.repo_name).to eql("foo") + end + + describe "#repo_enabled?" do + let(:cmd) { double("cmd") } + let(:output) { "Repo ID: repo123" } + + before do + allow(Mixlib::ShellOut).to receive(:new).and_return(cmd) + allow(cmd).to receive(:run_command) + allow(cmd).to receive(:stdout).and_return(output) + end + + context "when the repo provided matches the output" do + it "returns true" do + expect(provider.repo_enabled?("repo123")).to eq(true) + end + end + + context "when the repo provided does not match the output" do + it "returns false" do + expect(provider.repo_enabled?("differentrepo")).to eq(false) + end + end + end +end diff --git a/spec/unit/resource/rhsm_subscription_spec.rb b/spec/unit/resource/rhsm_subscription_spec.rb new file mode 100644 index 0000000000..0160624f39 --- /dev/null +++ b/spec/unit/resource/rhsm_subscription_spec.rb @@ -0,0 +1,93 @@ +# +# Copyright:: Copyright 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 "spec_helper" + +describe Chef::Resource::RhsmSubscription do + let(:resource) { Chef::Resource::RhsmSubscription.new("foo") } + let(:provider) { resource.provider_for_action(:attach) } + + it "has a resource name of :rhsm_subscription" do + expect(resource.resource_name).to eql(:rhsm_subscription) + end + + it "has a default action of attach" do + expect(resource.action).to eql([:attach]) + end + + it "the pool_id property is the name property" do + expect(resource.pool_id).to eql("foo") + end + + describe "#subscription_attached?" do + let(:cmd) { double("cmd") } + let(:output) { "Pool ID: pool123" } + + before do + allow(Mixlib::ShellOut).to receive(:new).and_return(cmd) + allow(cmd).to receive(:run_command) + allow(cmd).to receive(:stdout).and_return(output) + end + + context "when the pool provided matches the output" do + it "returns true" do + expect(provider.subscription_attached?("pool123")).to eq(true) + end + end + + context "when the pool provided does not match the output" do + it "returns false" do + expect(provider.subscription_attached?("differentpool")).to eq(false) + end + end + end + + describe "#serials_by_pool" do + let(:cmd) { double("cmd") } + let(:output) do + <<~EOL + Key1: value1 + Pool ID: pool1 + Serial: serial1 + Key2: value2 + + Key1: value1 + Pool ID: pool2 + Serial: serial2 + Key2: value2 +EOL + end + + it "parses the output correctly" do + allow(Mixlib::ShellOut).to receive(:new).and_return(cmd) + allow(cmd).to receive(:run_command) + allow(cmd).to receive(:stdout).and_return(output) + + expect(provider.serials_by_pool["pool1"]).to eq("serial1") + expect(provider.serials_by_pool["pool2"]).to eq("serial2") + end + end + + describe "#pool_serial" do + let(:serials) { { "pool1" => "serial1", "pool2" => "serial2" } } + + it "returns the serial for a given pool" do + allow(provider).to receive(:serials_by_pool).and_return(serials) + expect(provider.pool_serial("pool1")).to eq("serial1") + end + end +end |