diff options
103 files changed, 2715 insertions, 422 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 562e43e797..d6ca06036d 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -30,6 +30,7 @@ Please include the stacktrace.out output or link to a gist of it, if there is on This issue tracker is for the code contained within this repo -- `chef-client`, base `knife` functionality (not plugins), `chef-apply`, `chef-solo`, `chef-client -z`, etc. -* [Server issues](https://github.com/chef/chef-server/issues/new) +* Requests for new or alternative functionality should be made to [feedback.chef.io](https://feedback.chef.io/forums/301644-chef-product-feedback/category/110832-chef-client) +* [Chef Server issues](https://github.com/chef/chef-server/issues/new) * [ChefDK issues](https://github.com/chef/chef-dk/issues/new) * Cookbook Issues (see the https://github.com/chef-cookbooks repos or search [Supermarket](https://supermarket.chef.io) or GitHub/Google) diff --git a/.gitignore b/.gitignore index 144369156c..03d53ceb10 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ tags */tags *~ .chef +results # You should check in your Gemfile.lock in applications, and not in gems external_tests/*.lock diff --git a/.travis.yml b/.travis.yml index d2e7e91e6c..ed7fffc22b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,11 @@ cache: bundler # Early warning system to catch if Rubygems breaks something before_install: - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2) + - gem --version + - gem uninstall bundler -a -x + - rvm @global do gem uninstall bundler -a -x - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2) + - bundle --version - rm -f .bundle/config bundler_args: --without changelog development docgen guard maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen @@ -40,7 +44,7 @@ matrix: script: sudo -E $(which bundle) exec rake spec; # also remove integration / external tests bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen - - rvm: ruby-head + - rvm: 2.4.0 sudo: true script: sudo -E $(which bundle) exec rake spec; # also remove integration / external tests @@ -81,6 +85,8 @@ matrix: # The chefspec tests + bundler cache + "gem update --system" interact badly :/ # (Cucumber doesn't start.) before_install: + - gem uninstall bundler -a -x + - rvm @global do gem uninstall bundler -a -x - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2) - bundle config --local without server:docgen:maintenance:omnibus_package:development:ruby_prof:pry script: tasks/bin/run_external_test $TEST_GEM rake @@ -230,42 +236,43 @@ matrix: env: - CENTOS=7 - KITCHEN_YAML=.kitchen.travis.yml - - rvm: 2.3.3 - services: docker - sudo: required - gemfile: kitchen-tests/Gemfile - before_install: - - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2) - - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2) - bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen - before_script: - - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER ) - - cd kitchen-tests - script: - - bundle exec kitchen test webapp-fedora-latest - after_failure: - - cat .kitchen/logs/kitchen.log - env: - - FEDORA=latest - - KITCHEN_YAML=.kitchen.travis.yml - - rvm: 2.3.3 - services: docker - sudo: required - gemfile: kitchen-tests/Gemfile - before_install: - - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2) - - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2) - bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen - before_script: - - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER ) - - cd kitchen-tests - script: - - bundle exec kitchen test webapp-amazonlinux - after_failure: - - cat .kitchen/logs/kitchen.log - env: - - AMAZONLINUX=LATEST - - KITCHEN_YAML=.kitchen.travis.yml +# - rvm: 2.3.3 +# services: docker +# sudo: required +# gemfile: kitchen-tests/Gemfile +# before_install: +# - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2) +# - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2) +# bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen +# before_script: +# - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER ) +# - cd kitchen-tests +# script: +# - bundle exec kitchen test webapp-fedora-latest +# after_failure: +# - cat .kitchen/logs/kitchen.log +# env: +# - FEDORA=latest +# - KITCHEN_YAML=.kitchen.travis.yml +# can re-enable amazonlinux when we get a build in current that contains the crypto libs added in #5687 +# - rvm: 2.3.3 +# services: docker +# sudo: required +# gemfile: kitchen-tests/Gemfile +# before_install: +# - gem update --system $(grep rubygems omnibus_overrides.rb | cut -d'"' -f2) +# - gem install bundler -v $(grep bundler omnibus_overrides.rb | cut -d'"' -f2) +# bundler_args: --without changelog development docgen guard integration maintenance omnibus_package tools aix bsd mac_os_x solaris windows --frozen +# before_script: +# - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER ) +# - cd kitchen-tests +# script: +# - travis_wait bundle exec kitchen test webapp-amazonlinux +# after_failure: +# - cat .kitchen/logs/kitchen.log +# env: +# - AMAZONLINUX=LATEST +# - KITCHEN_YAML=.kitchen.travis.yml - rvm: 2.3.3 services: docker sudo: required @@ -324,9 +331,6 @@ matrix: - sudo cat /var/log/squid3/cache.log - sudo cat /var/log/squid3/access.log - allow_failures: - - rvm: ruby-head - notifications: on_change: true on_failure: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 5432fb7877..4f7fdcd3f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,39 @@ This changelog reflects the current state of chef's master branch on github and may not reflect the current released version of chef, which is [![Gem Version](https://badge.fury.io/rb/chef.svg)](https://badge.fury.io/rb/chef). -## [v12.18.19](https://github.com/chef/chef/tree/v12.18.19) (2017-01-04) -[Full Changelog](https://github.com/chef/chef/compare/v12.17.44...v12.18.19) +## [v12.19.4](https://github.com/chef/chef/tree/v12.19.4) (2017-02-01) +[Full Changelog](https://github.com/chef/chef/compare/v12.18.31...v12.19.4) + +**Merged pull requests:** + +- Use CIDR notation rather than netmask in route-eth0 file [\#5772](https://github.com/chef/chef/pull/5772) ([tduffield](https://github.com/tduffield)) +- Direct feature requests to feedback.chef.io [\#5759](https://github.com/chef/chef/pull/5759) ([tduffield](https://github.com/tduffield)) +- Bump minor version to 12.19 [\#5755](https://github.com/chef/chef/pull/5755) ([scottopherson](https://github.com/scottopherson)) +- Ruby 2.3 doesn't have casecmp?. Use casecmp instead [\#5751](https://github.com/chef/chef/pull/5751) ([tduffield](https://github.com/tduffield)) +- favor metadata.json over metadata.rb [\#5750](https://github.com/chef/chef/pull/5750) ([lamont-granquist](https://github.com/lamont-granquist)) +- Use new `fips\_mode` variable to define whether to build with FIPS [\#5746](https://github.com/chef/chef/pull/5746) ([tduffield](https://github.com/tduffield)) +- Ensure ssh search paginates correctly [\#5744](https://github.com/chef/chef/pull/5744) ([thommay](https://github.com/thommay)) +- Pin nio4r gem to avoid install error [\#5743](https://github.com/chef/chef/pull/5743) ([tduffield](https://github.com/tduffield)) +- Do not modify File's new\_resource during why-run [\#5742](https://github.com/chef/chef/pull/5742) ([scottopherson](https://github.com/scottopherson)) +- Add gems for ECC algorithm support to omnibus. [\#5736](https://github.com/chef/chef/pull/5736) ([rhass](https://github.com/rhass)) +- make it a trifle clearer that server issues don't belong here [\#5734](https://github.com/chef/chef/pull/5734) ([thommay](https://github.com/thommay)) +- dh/url support cab [\#5732](https://github.com/chef/chef/pull/5732) ([dheerajd-msys](https://github.com/dheerajd-msys)) +- Add myself as core maintainer [\#5728](https://github.com/chef/chef/pull/5728) ([tduffield](https://github.com/tduffield)) +- Raise NamedSecurityInfo related exception using HR result. [\#5727](https://github.com/chef/chef/pull/5727) ([Aliasgar16](https://github.com/Aliasgar16)) +- pass true as 2nd args for Net::SSH.configuration\_for by default. [\#5726](https://github.com/chef/chef/pull/5726) ([sawanoboly](https://github.com/sawanoboly)) +- Added module\_version attribute for dsc\_resource for SxS support [\#5701](https://github.com/chef/chef/pull/5701) ([Aliasgar16](https://github.com/Aliasgar16)) +- Bump net-ssh to v4, add dependencies for ed25519 support [\#5687](https://github.com/chef/chef/pull/5687) ([onlyhavecans](https://github.com/onlyhavecans)) +- Initial habitat plan for chef-client [\#5677](https://github.com/chef/chef/pull/5677) ([adamhjk](https://github.com/adamhjk)) + +## [v12.18.31](https://github.com/chef/chef/tree/v12.18.31) (2017-01-11) +[Full Changelog](https://github.com/chef/chef/compare/v12.17.44...v12.18.31) **Implemented enhancements:** +- yum\_repository: Allow baseurl to be an array & allow fastestmirror\_enabled false [\#5708](https://github.com/chef/chef/pull/5708) ([tas50](https://github.com/tas50)) +- Adding returns property to chocolatey\_package resource [\#5688](https://github.com/chef/chef/pull/5688) ([Vasu1105](https://github.com/Vasu1105)) - Code cleanup in the user provider [\#5674](https://github.com/chef/chef/pull/5674) ([lamont-granquist](https://github.com/lamont-granquist)) - Code cleanup in the group provider [\#5673](https://github.com/chef/chef/pull/5673) ([lamont-granquist](https://github.com/lamont-granquist)) -- Formally deprecate run\_command [\#5666](https://github.com/chef/chef/pull/5666) ([lamont-granquist](https://github.com/lamont-granquist)) +- Core: Formally deprecate run\_command [\#5666](https://github.com/chef/chef/pull/5666) ([lamont-granquist](https://github.com/lamont-granquist)) - Set MSI Scheduled Task name to match chef-client cookbook managed name [\#5657](https://github.com/chef/chef/pull/5657) ([mwrock](https://github.com/mwrock)) - remove Chef::Platform::HandlerMap [\#5636](https://github.com/chef/chef/pull/5636) ([lamont-granquist](https://github.com/lamont-granquist)) - Core: Properly deprecate old Chef::Platform methods [\#5631](https://github.com/chef/chef/pull/5631) ([lamont-granquist](https://github.com/lamont-granquist)) @@ -20,6 +46,10 @@ This changelog reflects the current state of chef's master branch on github and - Fix Data Collector organization parsing regex [\#5630](https://github.com/chef/chef/pull/5630) ([adamleff](https://github.com/adamleff)) - Core: Use object ID when detected unprocessed Resources [\#5604](https://github.com/chef/chef/pull/5604) ([adamleff](https://github.com/adamleff)) +**Merged pull requests:** + +- Core: fix node attribute "unless" API methods [\#5717](https://github.com/chef/chef/pull/5717) ([lamont-granquist](https://github.com/lamont-granquist)) + ## [v12.17.44](https://github.com/chef/chef/tree/v12.17.44) (2016-12-07) [Full Changelog](https://github.com/chef/chef/compare/v12.16.42...v12.17.44) diff --git a/Dockerfile b/Dockerfile index e3dea91a71..ea79037581 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM busybox MAINTAINER Chef Software, Inc. <docker@chef.io> ARG CHANNEL=stable -ARG VERSION=12.17.44 +ARG VERSION=12.18.31 RUN wget "http://packages.chef.io/files/${CHANNEL}/chef/${VERSION}/el/5/chef-${VERSION}-1.el5.x86_64.rpm" -O /tmp/chef-client.rpm && \ rpm2cpio /tmp/chef-client.rpm | cpio -idmv && \ diff --git a/Gemfile.lock b/Gemfile.lock index 778bebea26..c53b9af3ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/chef/chef-server - revision: 2d06ce7ef5976e2a410906f60152142bf90a17fb + revision: 96c04f9941f96c8be993b7103a0deb221f054120 specs: oc-chef-pedant (2.2.0) activesupport (>= 4.2.7.1, < 6.0) @@ -16,7 +16,7 @@ GIT GIT remote: https://github.com/chef/chefstyle.git - revision: c2076d117ff4307faf755ecc23eb2892aa20807a + revision: f3bc51612667e069f736f8ff18cf0bc0c18098fb branch: master specs: chefstyle (0.4.0) @@ -24,7 +24,7 @@ GIT GIT remote: https://github.com/rubysec/bundler-audit.git - revision: 044d056961dbc4b70d236a354a9cc86af54e0ae2 + revision: 80ae638e72df4c218da0e7a485ea2ee73aa257f2 specs: bundler-audit (0.5.0) bundler (~> 1.2) @@ -47,10 +47,10 @@ GIT PATH remote: . specs: - chef (12.18.19) + chef (12.19.4) addressable bundler (>= 1.10) - chef-config (= 12.18.19) + chef-config (= 12.19.4) chef-zero (>= 4.8) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -63,7 +63,7 @@ PATH mixlib-log (~> 1.3) mixlib-shellout (~> 2.0) net-sftp (~> 2.1, >= 2.1.2) - net-ssh (>= 2.9, < 4.0) + net-ssh (>= 2.9, < 5.0) net-ssh-multi (~> 1.1) ohai (>= 8.6.0.alpha.1, < 9) plist (~> 3.2) @@ -76,10 +76,10 @@ PATH specinfra (~> 2.10) syslog-logger (~> 1.6) uuidtools (~> 2.1.5) - chef (12.18.19-universal-mingw32) + chef (12.19.4-universal-mingw32) addressable bundler (>= 1.10) - chef-config (= 12.18.19) + chef-config (= 12.19.4) chef-zero (>= 4.8) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -93,7 +93,7 @@ PATH mixlib-log (~> 1.3) mixlib-shellout (~> 2.0) net-sftp (~> 2.1, >= 2.1.2) - net-ssh (>= 2.9, < 4.0) + net-ssh (>= 2.9, < 5.0) net-ssh-multi (~> 1.1) ohai (>= 8.6.0.alpha.1, < 9) plist (~> 3.2) @@ -120,7 +120,7 @@ PATH PATH remote: chef-config specs: - chef-config (12.18.19) + chef-config (12.19.4) addressable fuzzyurl mixlib-config (~> 2.0) @@ -129,7 +129,7 @@ PATH GEM remote: https://rubygems.org/ specs: - activesupport (5.0.0.1) + activesupport (5.0.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) @@ -139,38 +139,38 @@ GEM mixlib-cli (~> 1.4) artifactory (2.5.1) ast (2.3.0) - aws-sdk (2.6.40) - aws-sdk-resources (= 2.6.40) - aws-sdk-core (2.6.40) + aws-sdk (2.7.0) + aws-sdk-resources (= 2.7.0) + aws-sdk-core (2.7.0) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.6.40) - aws-sdk-core (= 2.6.40) + aws-sdk-resources (2.7.0) + aws-sdk-core (= 2.7.0) aws-sigv4 (1.0.0) backports (3.6.8) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - builder (3.2.2) + builder (3.2.3) byebug (9.0.6) chef-api (0.7.0) logify (~> 0.1) mime-types - chef-provisioning (2.0.2) + chef-provisioning (2.1.0) cheffish (~> 4.0) inifile (>= 2.0.2) mixlib-install (>= 1.0, < 3.0) net-scp (~> 1.0) - net-ssh (>= 2.9, < 4.0) - net-ssh-gateway (~> 1.2.0) + net-ssh (>= 2.9, < 5.0) + net-ssh-gateway (~> 1.2) winrm-fs (~> 1.0) chef-sugar (3.4.0) - chef-zero (5.1.1) + chef-zero (5.2.0) ffi-yajl (~> 2.2) hashie (>= 2.0, < 4.0) mixlib-log (~> 1.3) rack (~> 2.0) uuidtools (~> 2.1) - cheffish (4.0.0) + cheffish (4.1.0) chef-zero (~> 5.0) net-ssh chefspec (5.3.0) @@ -184,7 +184,7 @@ GEM simplecov url coderay (1.1.1) - concurrent-ruby (1.0.2) + concurrent-ruby (1.0.4) cucumber (2.4.0) builder (>= 2.1.2) cucumber-core (~> 1.5.0) @@ -197,7 +197,7 @@ GEM gherkin (~> 4.0) cucumber-wire (0.0.1) debug_inspector (0.0.2) - diff-lcs (1.2.5) + diff-lcs (1.3) docile (1.1.5) domain_name (0.5.20161129) unf (>= 0.0.5, < 1.0.0) @@ -205,21 +205,21 @@ GEM ethon (0.10.1) ffi (>= 1.3.0) excon (0.54.0) - faraday (0.10.0) + faraday (0.11.0) multipart-post (>= 1.2, < 3) faraday-http-cache (2.0.0) faraday (~> 0.8) - faraday_middleware (0.10.1) + faraday_middleware (0.11.0.1) faraday (>= 0.7.4, < 1.0) fauxhai (3.10.0) net-ssh - ffi (1.9.14) - ffi (1.9.14-x86-mingw32) + ffi (1.9.17) + ffi (1.9.17-x86-mingw32) ffi-win32-extensions (1.0.3) ffi ffi-yajl (2.3.0) libyajl2 (~> 1.2) - foodcritic (8.1.0) + foodcritic (8.2.0) cucumber-core (>= 1.3) erubis nokogiri (>= 1.5, < 2.0) @@ -259,7 +259,7 @@ GEM iniparse (1.4.2) ipaddress (0.8.3) jmespath (1.3.1) - json (2.0.2) + json (2.0.3) kitchen-docker (2.6.0) test-kitchen (>= 1.0.0) kitchen-ec2 (1.2.0) @@ -268,12 +268,12 @@ GEM multi_json retryable (~> 2.0) test-kitchen (~> 1.4, >= 1.4.1) - kitchen-sync (2.1.1) + kitchen-sync (2.1.2) net-sftp test-kitchen (>= 1.0.0) - kitchen-vagrant (0.21.1) + kitchen-vagrant (1.0.0) test-kitchen (~> 1.4) - knife-windows (1.7.1) + knife-windows (1.8.0) winrm (~> 2.1) winrm-elevated (~> 1.0) launchy (2.4.3) @@ -290,13 +290,13 @@ GEM mime-types-data (3.2016.0521) mini_portile2 (2.1.0) minitest (5.10.1) - mixlib-archive (0.2.0) + mixlib-archive (0.3.0) mixlib-log mixlib-authentication (1.4.1) mixlib-log mixlib-cli (1.7.0) mixlib-config (2.2.4) - mixlib-install (2.1.9) + mixlib-install (2.1.10) artifactory mixlib-shellout mixlib-versioning @@ -317,7 +317,7 @@ GEM net-ssh (>= 2.6.5) net-sftp (2.1.2) net-ssh (>= 2.6.5) - net-ssh (3.2.0) + net-ssh (4.0.1) net-ssh-gateway (1.2.0) net-ssh (>= 2.6.5) net-ssh-multi (1.2.1) @@ -325,9 +325,9 @@ GEM net-ssh-gateway (>= 1.2.0) net-telnet (0.1.1) netrc (0.11.0) - nokogiri (1.6.8.1) + nokogiri (1.7.0.1) mini_portile2 (~> 2.1.0) - nokogiri (1.6.8.1-x86-mingw32) + nokogiri (1.7.0.1-x86-mingw32) mini_portile2 (~> 2.1.0) nori (2.6.0) octokit (4.6.2) @@ -399,7 +399,7 @@ GEM json websocket (~> 1.0) rack (2.0.1) - rainbow (2.1.0) + rainbow (2.2.1) rake (11.3.0) rb-readline (0.5.3) rest-client (2.0.0) @@ -411,7 +411,7 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) - retriable (2.1.0) + retriable (3.0.0) retryable (2.0.4) rspec (3.5.0) rspec-core (~> 3.5.0) @@ -450,7 +450,7 @@ GEM sawyer (0.8.1) addressable (>= 2.3.5, < 2.6) faraday (~> 0.8, < 1.0) - serverspec (2.37.2) + serverspec (2.38.0) multi_json rspec (~> 3.0) rspec-its @@ -462,9 +462,9 @@ GEM simplecov-html (~> 0.10.0) simplecov-html (0.10.0) slop (3.6.0) - specinfra (2.66.2) + specinfra (2.66.5) net-scp - net-ssh (>= 2.7, < 4.0) + net-ssh (>= 2.7, < 5.0) net-telnet sfl stove (4.1.1) @@ -472,12 +472,12 @@ GEM logify (~> 0.2) syslog-logger (1.6.8) systemu (2.6.5) - test-kitchen (1.14.2) + test-kitchen (1.15.0) mixlib-install (>= 1.2, < 3.0) mixlib-shellout (>= 1.2, < 3.0) net-scp (~> 1.1) - net-ssh (>= 2.9, < 4.0) - net-ssh-gateway (~> 1.2.0) + net-ssh (>= 2.9, < 5.0) + net-ssh-gateway (~> 1.2) safe_yaml (~> 1.0) thor (~> 0.18) thor (0.19.4) @@ -502,7 +502,7 @@ GEM unf_ext unf_ext (0.0.7.2) unf_ext (0.0.7.2-x86-mingw32) - unicode-display_width (1.1.2) + unicode-display_width (1.1.3) url (0.3.2) uuidtools (2.1.5) vagrant-wrapper (2.0.3) @@ -527,7 +527,7 @@ GEM ffi-win32-extensions windows-api (0.4.4) win32-api (>= 1.4.5) - winrm (2.1.1) + winrm (2.1.2) builder (>= 2.1.2) erubis (~> 2.7) gssapi (~> 1.2) @@ -546,7 +546,7 @@ GEM winrm (~> 2.0) wmi-lite (1.0.0) yajl-ruby (1.3.0) - yard (0.9.5) + yard (0.9.8) yard-classmethods (1.0.0) yard diff --git a/HISTORY.md b/HISTORY.md index 9313404448..acce953a47 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,29 @@ +## [v12.18.31](https://github.com/chef/chef/tree/v12.18.31) (2017-01-11) +[Full Changelog](https://github.com/chef/chef/compare/v12.17.44...v12.18.31) + +**Implemented enhancements:** + +- yum\_repository: Allow baseurl to be an array & allow fastestmirror\_enabled false [\#5708](https://github.com/chef/chef/pull/5708) ([tas50](https://github.com/tas50)) +- Adding returns property to chocolatey\_package resource [\#5688](https://github.com/chef/chef/pull/5688) ([Vasu1105](https://github.com/Vasu1105)) +- Code cleanup in the user provider [\#5674](https://github.com/chef/chef/pull/5674) ([lamont-granquist](https://github.com/lamont-granquist)) +- Code cleanup in the group provider [\#5673](https://github.com/chef/chef/pull/5673) ([lamont-granquist](https://github.com/lamont-granquist)) +- Core: Formally deprecate run\_command [\#5666](https://github.com/chef/chef/pull/5666) ([lamont-granquist](https://github.com/lamont-granquist)) +- Set MSI Scheduled Task name to match chef-client cookbook managed name [\#5657](https://github.com/chef/chef/pull/5657) ([mwrock](https://github.com/mwrock)) +- remove Chef::Platform::HandlerMap [\#5636](https://github.com/chef/chef/pull/5636) ([lamont-granquist](https://github.com/lamont-granquist)) +- Core: Properly deprecate old Chef::Platform methods [\#5631](https://github.com/chef/chef/pull/5631) ([lamont-granquist](https://github.com/lamont-granquist)) + +**Fixed bugs:** + +- Fix error thrown by solo when run on Windows as SYSTEM [\#5693](https://github.com/chef/chef/pull/5693) ([scottopherson](https://github.com/scottopherson)) +- Report a blank resource if sensitive is enabled [\#5668](https://github.com/chef/chef/pull/5668) ([afiune](https://github.com/afiune)) +- Ensure node.docker? returns boolean [\#5645](https://github.com/chef/chef/pull/5645) ([andrewjamesbrown](https://github.com/andrewjamesbrown)) +- Fix Data Collector organization parsing regex [\#5630](https://github.com/chef/chef/pull/5630) ([adamleff](https://github.com/adamleff)) +- Core: Use object ID when detected unprocessed Resources [\#5604](https://github.com/chef/chef/pull/5604) ([adamleff](https://github.com/adamleff)) + +**Merged pull requests:** + +- Core: fix node attribute "unless" API methods [\#5717](https://github.com/chef/chef/pull/5717) ([lamont-granquist](https://github.com/lamont-granquist)) + ## [v12.17.44](https://github.com/chef/chef/tree/v12.17.44) (2016-12-07) [Full Changelog](https://github.com/chef/chef/compare/v12.16.42...v12.17.44) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 87f92de274..0034f46adc 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -44,6 +44,7 @@ To mention the team, use @chef/client-core * [Steven Murawski](https://github.com/smurawski) * [Steven Danna](https://github.com/stevendanna) * [Tim Smith](https://github.com/tas50) +* [Tom Duffield](https://github.com/tduffield) * [Tyler Ball](https://github.com/tyler-ball) ## Chef Provisioning diff --git a/MAINTAINERS.toml b/MAINTAINERS.toml index 1f577b4a24..a46953aac1 100644 --- a/MAINTAINERS.toml +++ b/MAINTAINERS.toml @@ -50,6 +50,7 @@ Maintainers for the Chef client, Ohai, mixlibs, ChefDK, ChefSpec, Foodcritic, ch "smurawski", "stevendanna", "tas50", + "tduffield", "tyler-ball" ] @@ -378,3 +379,7 @@ The specific components of Chef related to a given platform - including (but not [people.thehar] Name = "Harley Alaniz" GitHub = "thehar" + + [people.tduffield] + Name = "Tom Duffield" + GitHub = "tduffield" diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 6d60f16065..d9c33dc769 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,23 +4,26 @@ _This file holds "in progress" release notes for the current release under devel ## Highlighted enhancements for this release: +- You can now specify the acceptable return codes from the chocolatey_package resource using the returns property. - You can now enable chef-client to run as a scheduled task directly from the client MSI on Windows hosts. +- The package provider now supports DNF packages for Fedora and upcoming RHEL releases ## Highlighted bug fixes for this release: -- Fixed exposure of sensitive data of resources marked as sensitive inside Reporting. Before you - were able to see the sensitive data on the Run History tab in the Chef Manage Console. Now we - are sending a new blank resource if the resource is marked as sensitive, this way we will not - compromise any sensitive data. +- Fixed exposure of sensitive data of resources marked as sensitive inside Reporting. Before you were able to see the sensitive data on the Run History tab in the Chef Manage Console. Now we are sending a new blank resource if the resource is marked as sensitive, this way we will not compromise any sensitive data. - _Note: Old data that was already sent to Reporting marked as sensitive will continue to be - displayed. Apologies._ + _Note: Old data that was already sent to Reporting marked as sensitive will continue to be displayed. Apologies._ ## New deprecations introduced in this release: -### Chef Platform Methods +### Chef::Platform Helper Methods - **Deprecation ID**: 13 -- **Remediation Docs**: <https://docs.chef.io/chef_platform_methods.html> +- **Remediation Docs**: <https://docs.chef.io/deprecations_chef_platform_methods.html> - **Expected Removal**: Chef 13 (April 2017) +### run_command Helper Method + +- **Deprecation ID**: 14 +- **Remediation Docs**: <https://docs.chef.io/deprecations_run_command.html> +- **Expected Removal**: Chef 13 (April 2017) @@ -1 +1 @@ -12.18.19
\ No newline at end of file +12.19.4
\ No newline at end of file diff --git a/acceptance/Gemfile b/acceptance/Gemfile index 59f232fcd3..77b45e733d 100644 --- a/acceptance/Gemfile +++ b/acceptance/Gemfile @@ -14,3 +14,8 @@ gem "berkshelf", "4.3.5" # until 2.0.0 is fixed for unstable packages gem "mixlib-install", "1.2.3" + +# nio4r 2.x was throwing a "could not install" error because of a Ruby version +# conflict (that didn't actually exist). Since the only gem that really needs +# it is celluloid, let's just pin it until it becomes a bigger problem. +gem "nio4r", ">= 1.1.0", "< 2.0.0" diff --git a/acceptance/Gemfile.lock b/acceptance/Gemfile.lock index 8eed594103..b52a1c7a29 100644 --- a/acceptance/Gemfile.lock +++ b/acceptance/Gemfile.lock @@ -12,13 +12,13 @@ GEM addressable (2.5.0) public_suffix (~> 2.0, >= 2.0.2) artifactory (2.5.1) - aws-sdk (2.6.43) - aws-sdk-resources (= 2.6.43) - aws-sdk-core (2.6.43) + aws-sdk (2.7.0) + aws-sdk-resources (= 2.7.0) + aws-sdk-core (2.7.0) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.6.43) - aws-sdk-core (= 2.6.43) + aws-sdk-resources (2.7.0) + aws-sdk-core (= 2.7.0) aws-sigv4 (1.0.0) berkshelf (4.3.5) addressable (~> 2.3, >= 2.3.4) @@ -50,20 +50,20 @@ GEM buff-ruby_engine (0.1.0) buff-shell_out (0.2.0) buff-ruby_engine (~> 0.1.0) - builder (3.2.2) + builder (3.2.3) celluloid (0.16.0) timers (~> 4.0.0) celluloid-io (0.16.2) celluloid (>= 0.16.0) nio4r (>= 1.1.0) - chef-config (12.17.44) + chef-config (12.18.31) addressable fuzzyurl mixlib-config (~> 2.0) mixlib-shellout (~> 2.0) cleanroom (1.0.0) coderay (1.1.1) - diff-lcs (1.2.5) + diff-lcs (1.3) docker-api (1.33.1) excon (>= 0.38.0) json @@ -71,7 +71,7 @@ GEM excon (0.54.0) faraday (0.9.2) multipart-post (>= 1.2, < 3) - ffi (1.9.14) + ffi (1.9.17) fuzzyurl (0.9.0) gssapi (1.2.0) ffi (>= 1.0.1) @@ -80,7 +80,7 @@ GEM hashie (3.4.6) hitimes (1.2.4) httpclient (2.7.2) - inspec (1.8.0) + inspec (1.9.0) hashie (~> 3.4) json (>= 1.8, < 3.0) method_source (~> 0.8) @@ -96,7 +96,7 @@ GEM thor (~> 0.19) train (>= 0.22.0, < 1.0) jmespath (1.3.1) - json (2.0.2) + json (2.0.3) kitchen-ec2 (1.2.0) aws-sdk (~> 2) excon @@ -107,7 +107,7 @@ GEM hashie (~> 3.4) inspec (>= 0.34.0, < 2.0.0) test-kitchen (~> 1.6) - kitchen-vagrant (0.21.1) + kitchen-vagrant (1.0.0) test-kitchen (~> 1.4) little-plugger (1.1.4) logging (2.1.0) @@ -115,7 +115,7 @@ GEM multi_json (~> 1.10) method_source (0.8.2) minitar (0.5.4) - mixlib-archive (0.2.0) + mixlib-archive (0.3.0) mixlib-log mixlib-authentication (1.4.1) mixlib-log @@ -132,10 +132,10 @@ GEM multipart-post (2.0.0) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (3.2.0) + net-ssh (4.0.1) net-ssh-gateway (1.2.0) net-ssh (>= 2.6.5) - nio4r (2.0.0) + nio4r (1.2.1) nori (2.6.0) octokit (4.6.2) sawyer (~> 0.8.0, >= 0.5.3) @@ -196,23 +196,23 @@ GEM molinillo (~> 0.4.2) semverse (~> 1.1) sslshake (1.0.13) - test-kitchen (1.14.2) + test-kitchen (1.15.0) mixlib-install (>= 1.2, < 3.0) mixlib-shellout (>= 1.2, < 3.0) net-scp (~> 1.1) - net-ssh (>= 2.9, < 4.0) - net-ssh-gateway (~> 1.2.0) + net-ssh (>= 2.9, < 5.0) + net-ssh-gateway (~> 1.2) safe_yaml (~> 1.0) thor (~> 0.18) thor (0.19.4) timers (4.0.4) hitimes - train (0.22.0) + train (0.22.1) docker-api (~> 1.26) json (>= 1.8, < 3.0) mixlib-shellout (~> 2.0) net-scp (~> 1.2) - net-ssh (>= 2.9, < 4.0) + net-ssh (>= 2.9, < 5.0) winrm (~> 2.0) winrm-fs (~> 1.0) varia_model (0.4.1) @@ -220,7 +220,7 @@ GEM hashie (>= 2.0.2, < 4.0.0) windows_chef_zero (2.0.0) test-kitchen (>= 1.2.1) - winrm (2.1.1) + winrm (2.1.2) builder (>= 2.1.2) erubis (~> 2.7) gssapi (~> 1.2) @@ -249,9 +249,10 @@ DEPENDENCIES kitchen-inspec kitchen-vagrant mixlib-install (= 1.2.3) + nio4r (>= 1.1.0, < 2.0.0) test-kitchen windows_chef_zero winrm-elevated BUNDLED WITH - 1.13.6 + 1.12.5 diff --git a/appveyor.yml b/appveyor.yml index 08756d98ad..e3bf174e01 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,11 +20,12 @@ install: - systeminfo - winrm quickconfig -q - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% + - ps: $env:RUBYGEMS_VERSION=$(findstr rubygems omnibus_overrides.rb | %{ $_.split(" ")[3] }) + - ps: $env:BUNDLER_VERSION=$(findstr bundler omnibus_overrides.rb | %{ $_.split(" ")[3] }) - echo %PATH% - ruby --version - - gem update --system || gem update --system || gem update --system - - gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc - - update_rubygems + - gem update --system %RUBYGEMS_VERSION% || gem update --system %RUBYGEMS_VERSION% || gem update --system %RUBYGEMS_VERSION% + - gem install bundler -v %BUNDLER_VERSION% --quiet --no-ri --no-rdoc || gem install bundler -v %BUNDLER_VERSION% --quiet --no-ri --no-rdoc || gem install bundler -v %BUNDLER_VERSION% --quiet --no-ri --no-rdoc - gem --version - bundler --version - SET BUNDLE_IGNORE_CONFIG=true diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb index 3571edb22f..fd7e5d9556 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 = "12.18.19" + VERSION = "12.19.4" end # diff --git a/chef.gemspec b/chef.gemspec index 367761fbcc..2d5544aa4f 100644 --- a/chef.gemspec +++ b/chef.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |s| s.add_dependency "ohai", ">= 8.6.0.alpha.1", "< 9" s.add_dependency "ffi-yajl", "~> 2.2" - s.add_dependency "net-ssh", ">= 2.9", "< 4.0" + s.add_dependency "net-ssh", ">= 2.9", "< 5.0" s.add_dependency "net-ssh-multi", "~> 1.1" s.add_dependency "net-sftp", "~> 2.1", ">= 2.1.2" s.add_dependency "highline", "~> 1.6", ">= 1.6.9" diff --git a/habitat/default.toml b/habitat/default.toml new file mode 100644 index 0000000000..04385fc371 --- /dev/null +++ b/habitat/default.toml @@ -0,0 +1,11 @@ +# The Chef run interval in seconds +interval = 10 + +# The splay +splay = 10 + +# The default log level +log_level = "info" + +# The default run list +run_list = "" diff --git a/habitat/hooks/run b/habitat/hooks/run new file mode 100644 index 0000000000..0f3844dd5f --- /dev/null +++ b/habitat/hooks/run @@ -0,0 +1,8 @@ +#!/bin/sh +export GEM_HOME="{{pkg.path}}/ruby/2.3.0" +export GEM_PATH="$(hab pkg path core/ruby)/lib/ruby/gems/2.3.0:$(hab pkg path core/bundler):$GEM_HOME" +export APPBUNDLER_ALLOW_RVM=true + +exec 2>&1 +exec chef-solo --fork -i {{cfg.interval}} -s {{cfg.splay}} -l {{cfg.log_level}} -o {{cfg.run_list}} + diff --git a/habitat/plan.sh b/habitat/plan.sh new file mode 100644 index 0000000000..7a797842e2 --- /dev/null +++ b/habitat/plan.sh @@ -0,0 +1,100 @@ +pkg_name=chef-client +pkg_origin=chef +pkg_maintainer="The Chef Maintainers <humans@chef.io>" +pkg_description="The Chef Client" +pkg_version=$(cat ../VERSION) +pkg_source=nosuchfile.tar.gz +pkg_filename=${pkg_dirname}.tar.gz +pkg_license=('Apache-2.0') +pkg_bin_dirs=(bin) +pkg_build_deps=(core/make core/gcc core/coreutils core/git) +pkg_deps=(core/glibc core/ruby core/libxml2 core/libxslt core/libiconv core/xz core/zlib core/bundler core/openssl core/cacerts core/libffi) +pkg_svc_user=root + +do_download() { + build_line "Fake download! Creating archive of latest repository commit." + # source is in this repo, so we're going to create an archive from the + # appropriate path within the repo and place the generated tarball in the + # location expected by do_unpack + cd $PLAN_CONTEXT/../ + git archive --prefix=${pkg_name}-${pkg_version}/ --output=$HAB_CACHE_SRC_PATH/${pkg_filename} HEAD +} + +do_verify() { + build_line "Skipping checksum verification on the archive we just created." + return 0 +} + +do_prepare() { + export OPENSSL_LIB_DIR=$(pkg_path_for openssl)/lib + export OPENSSL_INCLUDE_DIR=$(pkg_path_for openssl)/include + export SSL_CERT_FILE=$(pkg_path_for cacerts)/ssl/cert.pem + + build_line "Setting link for /usr/bin/env to 'coreutils'" + [[ ! -f /usr/bin/env ]] && ln -s $(pkg_path_for coreutils)/bin/env /usr/bin/env + + return 0 +} + +do_build() { + export CPPFLAGS="${CPPFLAGS} ${CFLAGS}" + + local _bundler_dir=$(pkg_path_for bundler) + local _libxml2_dir=$(pkg_path_for libxml2) + local _libxslt_dir=$(pkg_path_for libxslt) + local _zlib_dir=$(pkg_path_for zlib) + + export GEM_HOME=${pkg_prefix} + export GEM_PATH=${_bundler_dir}:${GEM_HOME} + + export NOKOGIRI_CONFIG="--use-system-libraries --with-zlib-dir=${_zlib_dir} --with-xslt-dir=${_libxslt_dir} --with-xml2-include=${_libxml2_dir}/include/libxml2 --with-xml2-lib=${_libxml2_dir}/lib" + bundle config --local build.nokogiri '${NOKOGIRI_CONFIG}' + + bundle config --local silence_root_warning 1 + + # We need to add tzinfo-data to the Gemfile since we're not in an + # environment that has this from the OS + if [[ -z "`grep 'gem .*tzinfo-data.*' Gemfile`" ]]; then + echo 'gem "tzinfo-data"' >> Gemfile + fi + + bundle install --no-deployment --jobs 2 --retry 5 --path $pkg_prefix + + bundle exec 'cd ./chef-config && rake package' + bundle exec 'rake package' + mkdir -p gems-suck/gems + cp pkg/chef-$pkg_version.gem gems-suck/gems + cp chef-config/pkg/chef-config-$pkg_version.gem gems-suck/gems + bundle exec gem generate_index -d gems-suck + + sed -e "s#gem \"chef\".*#gem \"chef\", source: \"file://$HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck\"#" -i Gemfile + sed -e "s#gem \"chef-config\".*#gem \"chef-config\", source: \"file://$HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck\"#" -i Gemfile + #bundle config --local local.chef $HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck + #bundle config --local local.chef-config $HAB_CACHE_SRC_PATH/$pkg_dirname/gems-suck + + bundle install --no-deployment --jobs 2 --retry 5 --path $pkg_prefix + +} + +do_install() { + + mkdir -p $pkg_prefix/bin + + bundle exec appbundler $HAB_CACHE_SRC_PATH/$pkg_dirname $pkg_prefix/bin chef + bundle exec appbundler $HAB_CACHE_SRC_PATH/$pkg_dirname $pkg_prefix/bin ohai + + for binstub in ${pkg_prefix}/bin/*; do + build_line "Setting shebang for ${binstub} to 'ruby'" + [[ -f $binstub ]] && sed -e "s#/usr/bin/env ruby#$(pkg_path_for ruby)/bin/ruby#" -i $binstub + done + + if [[ `readlink /usr/bin/env` = "$(pkg_path_for coreutils)/bin/env" ]]; then + build_line "Removing the symlink we created for '/usr/bin/env'" + rm /usr/bin/env + fi +} + +# Stubs +do_strip() { + return 0 +} diff --git a/kitchen-tests/Berksfile.lock b/kitchen-tests/Berksfile.lock index bf6b9f2c95..6d8f40436a 100644 --- a/kitchen-tests/Berksfile.lock +++ b/kitchen-tests/Berksfile.lock @@ -1,12 +1,12 @@ DEPENDENCIES awesome_customers_rhel git: https://github.com/learn-chef/awesome_customers_rhel.git - revision: 1ac86593829610c0eab7a45d9c63c09a9cea1754 + revision: b576fcf2988e2cdf156e7ba6ff59a94d556e16f1 awesome_customers_rhel_wrapper path: cookbooks/awesome_customers_rhel_wrapper awesome_customers_ubuntu git: https://github.com/learn-chef/awesome_customers_ubuntu.git - revision: 71927c094d570e6fd0f8bfbcc02ebe3556af2a16 + revision: fea174c5855266f28218f76f00f6eff69e850244 awesome_customers_ubuntu_wrapper path: cookbooks/awesome_customers_ubuntu_wrapper base @@ -52,18 +52,18 @@ GRAPH sudo (>= 0.0.0) ubuntu (>= 0.0.0) users (>= 0.0.0) - build-essential (7.0.2) - compat_resource (>= 12.14) + build-essential (7.0.3) + compat_resource (>= 12.16.3) mingw (>= 1.1) seven_zip (>= 0.0.0) - chef-client (7.0.1) + chef-client (7.1.0) cron (>= 1.7.0) logrotate (>= 1.9.0) windows (>= 1.42.0) chef-sugar (3.4.0) chef_hostname (0.4.2) compat_resource (>= 0.0.0) - compat_resource (12.16.2) + compat_resource (12.16.3) cron (3.0.0) database (6.1.1) postgresql (>= 1.0.0) @@ -73,18 +73,18 @@ GRAPH compat_resource (>= 12.14.6) iis (5.0.5) windows (>= 1.34.6) - iptables (3.0.1) + iptables (3.1.0) compat_resource (>= 12.14.3) logrotate (2.1.0) compat_resource (>= 0.0.0) - mariadb (0.3.3) + mariadb (1.0.1) apt (>= 0.0.0) yum (>= 0.0.0) yum-epel (>= 0.0.0) - mingw (1.2.4) - compat_resource (>= 0.0.0) + mingw (1.2.5) + compat_resource (>= 12.16.3) seven_zip (>= 0.0.0) - multipackage (3.0.28) + multipackage (4.0.0) compat_resource (>= 0.0.0) mysql (7.2.0) smf (>= 0.0.0) @@ -95,12 +95,12 @@ GRAPH mysql (>= 6.0) nscd (4.1.0) compat_resource (>= 0.0.0) - ntp (3.2.0) - ohai (4.2.2) - compat_resource (>= 12.14) - openssh (2.1.0) + ntp (3.3.1) + ohai (4.2.3) + compat_resource (>= 12.14.7) + openssh (2.1.1) iptables (>= 1.0) - openssl (6.0.0) + openssl (6.1.1) php (1.5.0) build-essential (>= 0.0.0) iis (>= 0.0.0) @@ -108,9 +108,9 @@ GRAPH windows (>= 0.0.0) xml (>= 0.0.0) yum-epel (>= 0.0.0) - postgresql (5.1.0) - apt (>= 1.9.0) + postgresql (6.0.1) build-essential (>= 2.0.0) + compat_resource (>= 12.16.3) openssl (>= 4.0) rbac (1.0.3) resolver (1.3.1) @@ -119,16 +119,16 @@ GRAPH windows (>= 1.2.2) smf (2.2.8) rbac (>= 1.0.1) - sudo (3.1.0) + sudo (3.3.1) ubuntu (2.0.0) apt (>= 0.0.0) users (4.0.3) windows (2.1.1) ohai (>= 4.0.0) - xml (3.0.0) + xml (3.1.1) build-essential (>= 0.0.0) yum (4.1.0) - yum-epel (2.0.0) - compat_resource (>= 12.14.6) - yum-mysql-community (2.0.2) - compat_resource (>= 12.14.7) + yum-epel (2.1.1) + compat_resource (>= 12.16.3) + yum-mysql-community (2.0.3) + compat_resource (>= 12.16.3) diff --git a/kitchen-tests/Gemfile b/kitchen-tests/Gemfile index ad89269a75..4b6b595d1f 100644 --- a/kitchen-tests/Gemfile +++ b/kitchen-tests/Gemfile @@ -9,3 +9,4 @@ gem "kitchen-vagrant" gem "ridley" gem "test-kitchen" gem "vagrant-wrapper" +gem "rainbow", ">= 2.1.0", "< 2.2" diff --git a/kitchen-tests/Gemfile.lock b/kitchen-tests/Gemfile.lock index 957b478396..ec235ebcb8 100644 --- a/kitchen-tests/Gemfile.lock +++ b/kitchen-tests/Gemfile.lock @@ -4,15 +4,15 @@ GEM addressable (2.5.0) public_suffix (~> 2.0, >= 2.0.2) artifactory (2.5.1) - aws-sdk (2.6.32) - aws-sdk-resources (= 2.6.32) - aws-sdk-core (2.6.32) + aws-sdk (2.7.0) + aws-sdk-resources (= 2.7.0) + aws-sdk-core (2.7.0) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.6.32) - aws-sdk-core (= 2.6.32) + aws-sdk-resources (2.7.0) + aws-sdk-core (= 2.7.0) aws-sigv4 (1.0.0) - berkshelf (5.2.0) + berkshelf (5.4.0) addressable (~> 2.3, >= 2.3.4) berkshelf-api-client (>= 2.0.2, < 4.0) buff-config (~> 2.0) @@ -27,7 +27,7 @@ GEM retryable (~> 2.0) ridley (~> 5.0) solve (> 2.0, < 4.0) - thor (~> 0.19) + thor (~> 0.19, < 0.19.2) berkshelf-api-client (3.0.0) faraday (~> 0.9) httpclient (~> 2.7) @@ -40,29 +40,29 @@ GEM buff-ruby_engine (1.0.0) buff-shell_out (1.1.0) buff-ruby_engine (~> 1.0) - builder (3.2.2) + builder (3.2.3) celluloid (0.16.0) timers (~> 4.0.0) celluloid-io (0.16.2) celluloid (>= 0.16.0) nio4r (>= 1.1.0) - chef-config (12.16.42) + chef-config (12.18.31) addressable fuzzyurl mixlib-config (~> 2.0) mixlib-shellout (~> 2.0) cleanroom (1.0.0) coderay (1.1.1) - diff-lcs (1.2.5) - docker-api (1.33.0) + diff-lcs (1.3) + docker-api (1.33.1) excon (>= 0.38.0) json erubis (2.7.0) excon (0.54.0) faraday (0.9.2) multipart-post (>= 1.2, < 3) - ffi (1.9.14) - ffi (1.9.14-x86-mingw32) + ffi (1.9.17) + ffi (1.9.17-x86-mingw32) fuzzyurl (0.9.0) gssapi (1.2.0) ffi (>= 1.0.1) @@ -71,8 +71,8 @@ GEM hashie (3.4.6) hitimes (1.2.4) hitimes (1.2.4-x86-mingw32) - httpclient (2.8.2.4) - inspec (1.7.0) + httpclient (2.8.3) + inspec (1.9.0) hashie (~> 3.4) json (>= 1.8, < 3.0) method_source (~> 0.8) @@ -86,12 +86,12 @@ GEM rubyzip (~> 1.1) sslshake (~> 1) thor (~> 0.19) - train (>= 0.20.1, < 1.0) + train (>= 0.22.0, < 1.0) jmespath (1.3.1) - json (2.0.2) + json (2.0.3) kitchen-appbundle-updater (0.1.2) - kitchen-dokken (1.0.7) - docker-api (~> 1.32) + kitchen-dokken (1.1.0) + docker-api (~> 1.33) test-kitchen (~> 1.13) kitchen-ec2 (1.2.0) aws-sdk (~> 2) @@ -99,11 +99,11 @@ GEM multi_json retryable (~> 2.0) test-kitchen (~> 1.4, >= 1.4.1) - kitchen-inspec (0.16.1) + kitchen-inspec (0.17.0) hashie (~> 3.4) inspec (>= 0.34.0, < 2.0.0) test-kitchen (~> 1.6) - kitchen-vagrant (0.21.0) + kitchen-vagrant (1.0.0) test-kitchen (~> 1.4) little-plugger (1.1.4) logging (2.1.0) @@ -111,12 +111,12 @@ GEM multi_json (~> 1.10) method_source (0.8.2) minitar (0.5.4) - mixlib-archive (0.2.0) + mixlib-archive (0.3.0) mixlib-log mixlib-authentication (1.4.1) mixlib-log mixlib-config (2.2.4) - mixlib-install (2.1.7) + mixlib-install (2.1.10) artifactory mixlib-shellout mixlib-versioning @@ -127,15 +127,15 @@ GEM win32-process (~> 0.8.2) wmi-lite (~> 1.0) mixlib-versioning (1.1.0) - molinillo (0.5.4) + molinillo (0.5.5) multi_json (1.12.1) multipart-post (2.0.0) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (3.2.0) + net-ssh (4.0.1) net-ssh-gateway (1.2.0) net-ssh (>= 2.6.5) - nio4r (1.2.1) + nio4r (2.0.0) nori (2.6.0) octokit (4.6.2) sawyer (~> 0.8.0, >= 0.5.3) @@ -144,7 +144,7 @@ GEM coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - public_suffix (2.0.4) + public_suffix (2.0.5) rainbow (2.1.0) retryable (2.0.4) ridley (5.1.0) @@ -196,23 +196,23 @@ GEM molinillo (>= 0.5) semverse (>= 1.1, < 3.0) sslshake (1.0.13) - test-kitchen (1.14.0) + test-kitchen (1.15.0) mixlib-install (>= 1.2, < 3.0) mixlib-shellout (>= 1.2, < 3.0) net-scp (~> 1.1) - net-ssh (>= 2.9, < 4.0) - net-ssh-gateway (~> 1.2.0) + net-ssh (>= 2.9, < 5.0) + net-ssh-gateway (~> 1.2) safe_yaml (~> 1.0) thor (~> 0.18) - thor (0.19.4) + thor (0.19.1) timers (4.0.4) hitimes - train (0.22.0) + train (0.22.1) docker-api (~> 1.26) json (>= 1.8, < 3.0) mixlib-shellout (~> 2.0) net-scp (~> 1.2) - net-ssh (>= 2.9, < 4.0) + net-ssh (>= 2.9, < 5.0) winrm (~> 2.0) winrm-fs (~> 1.0) vagrant-wrapper (2.0.3) @@ -221,7 +221,7 @@ GEM hashie (>= 2.0.2, < 4.0.0) win32-process (0.8.3) ffi (>= 1.0.0) - winrm (2.1.0) + winrm (2.1.2) builder (>= 2.1.2) erubis (~> 2.7) gssapi (~> 1.2) @@ -230,7 +230,7 @@ GEM logging (>= 1.6.1, < 3.0) nori (~> 2.0) rubyntlm (~> 0.6.0, >= 0.6.1) - winrm-fs (1.0.0) + winrm-fs (1.0.1) erubis (~> 2.7) logging (>= 1.6.1, < 3.0) rubyzip (~> 1.1) @@ -248,9 +248,10 @@ DEPENDENCIES kitchen-ec2 kitchen-inspec kitchen-vagrant + rainbow (>= 2.1.0, < 2.2) ridley test-kitchen vagrant-wrapper BUNDLED WITH - 1.13.6 + 1.12.5 diff --git a/kitchen-tests/cookbooks/base/attributes/default.rb b/kitchen-tests/cookbooks/base/attributes/default.rb index ef273c969c..75e57cb27b 100644 --- a/kitchen-tests/cookbooks/base/attributes/default.rb +++ b/kitchen-tests/cookbooks/base/attributes/default.rb @@ -13,7 +13,6 @@ default["ubuntu"]["components"] = "main restricted universe multiverse" # # turn off old protocols client-side -default["openssh"]["client"]["rsa_authentication"] = "no" default["openssh"]["client"]["host_based_authentication"] = "no" # allow typical ssh v2 rsa/dsa/ecdsa key auth client-side default["openssh"]["client"]["pubkey_authentication"] = "yes" @@ -34,8 +33,6 @@ default["openssh"]["server"]["use_dns"] = "no" default["openssh"]["server"]["syslog_facility"] = "AUTH" # only allow access via ssh pubkeys, all other mechanisms including passwords are turned off for all users default["openssh"]["server"]["pubkey_authentication"] = "yes" -default["openssh"]["server"]["rhosts_rsa_authentication"] = "no" -default["openssh"]["server"]["rsa_authentication"] = "no" default["openssh"]["server"]["password_authentication"] = "no" default["openssh"]["server"]["host_based_authentication"] = "no" default["openssh"]["server"]["gssapi_authentication"] = "no" diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb index 3a395d979d..e61fd5e1d2 100644 --- a/lib/chef/chef_class.rb +++ b/lib/chef/chef_class.rb @@ -30,6 +30,7 @@ require "chef/platform/provider_priority_map" require "chef/platform/resource_priority_map" require "chef/platform/provider_handler_map" require "chef/platform/resource_handler_map" +require "chef/deprecated" require "chef/event_dispatch/dsl" require "chef/deprecated" diff --git a/lib/chef/cookbook/cookbook_version_loader.rb b/lib/chef/cookbook/cookbook_version_loader.rb index d253c956b2..b2305d3870 100644 --- a/lib/chef/cookbook/cookbook_version_loader.rb +++ b/lib/chef/cookbook/cookbook_version_loader.rb @@ -108,10 +108,10 @@ class Chef @uploaded_cookbook_version_file = File.join(cookbook_path, UPLOADED_COOKBOOK_VERSION_FILE) end - if File.exists?(File.join(cookbook_path, "metadata.rb")) - @metadata_filenames << File.join(cookbook_path, "metadata.rb") - elsif File.exists?(File.join(cookbook_path, "metadata.json")) + if File.exists?(File.join(cookbook_path, "metadata.json")) @metadata_filenames << File.join(cookbook_path, "metadata.json") + elsif File.exists?(File.join(cookbook_path, "metadata.rb")) + @metadata_filenames << File.join(cookbook_path, "metadata.rb") elsif @uploaded_cookbook_version_file @metadata_filenames << @uploaded_cookbook_version_file end diff --git a/lib/chef/deprecated.rb b/lib/chef/deprecated.rb index 5b0bac552e..76f66f723b 100644 --- a/lib/chef/deprecated.rb +++ b/lib/chef/deprecated.rb @@ -156,6 +156,26 @@ class Chef end end + class PropertyNameCollision < Base + def id + 11 + end + + def target + "property_name_collision.html" + end + end + + class LaunchdHashProperty < Base + def id + 12 + end + + def target + "launchd_hash_property.html" + end + end + class ChefPlatformMethods < Base def id 13 @@ -196,6 +216,16 @@ class Chef end end + class DnfPackageAllowDowngrade < Base + def id + 10 + end + + def target + "dnf_package_allow_downgrade.html" + end + end + class Generic < Base def url "https://docs.chef.io/chef_deprecations_client.html" diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb index 2d6dcef17e..864268a85e 100644 --- a/lib/chef/exceptions.rb +++ b/lib/chef/exceptions.rb @@ -525,5 +525,8 @@ This error is most often caused by network issues (proxies, etc) outside of chef super "Found multiple matching resources. #{matches_info.join("\n")}" end end + + # exception specific to invalid usage of 'dsc_resource' resource + class DSCModuleNameMissing < ArgumentError; end end end diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb index f827aca280..6797f6cab2 100644 --- a/lib/chef/knife/ssh.rb +++ b/lib/chef/knife/ssh.rb @@ -166,10 +166,10 @@ class Chef def configure_session list = config[:manual] ? @name_args[0].split(" ") : search_nodes if list.length == 0 - if @action_nodes.length == 0 + if @search_count == 0 ui.fatal("No nodes returned from search") else - ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes" : "node"} found, " + + ui.fatal("#{@search_count} #{@search_count > 1 ? "nodes" : "node"} found, " + "but does not have the required attribute to establish the connection. " + "Try setting another attribute to open the connection using --attribute.") end @@ -184,41 +184,56 @@ class Chef # 2) configuration file # 3) cloud attribute # 4) fqdn - if config[:attribute] - Chef::Log.debug("Using node attribute '#{config[:attribute]}' as the ssh target") - attribute = config[:attribute] + if node["config"] + Chef::Log.debug("Using node attribute '#{config[:attribute]}' as the ssh target: #{node["config"]}") + node["config"] elsif Chef::Config[:knife][:ssh_attribute] - Chef::Log.debug("Using node attribute #{Chef::Config[:knife][:ssh_attribute]}") - attribute = Chef::Config[:knife][:ssh_attribute] - elsif node[:cloud] && - node[:cloud][:public_hostname] && - !node[:cloud][:public_hostname].empty? - Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target") - attribute = "cloud.public_hostname" + Chef::Log.debug("Using node attribute #{Chef::Config[:knife][:ssh_attribute]}: #{node["knife_config"]}") + node["knife_config"] + elsif node["cloud"] && + node["cloud"]["public_hostname"] && + !node["cloud"]["public_hostname"].empty? + Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target: #{node["cloud"]["public_hostname"]}") + node["cloud"]["public_hostname"] else # falling back to default of fqdn - Chef::Log.debug("Using node attribute 'fqdn' as the ssh target") - attribute = "fqdn" + Chef::Log.debug("Using node attribute 'fqdn' as the ssh target: #{node["fqdn"]}") + node["fqdn"] end - attribute end def search_nodes list = Array.new query = Chef::Search::Query.new - @action_nodes = query.search(:node, @name_args[0])[0] - @action_nodes.each do |item| + required_attributes = { fqdn: ["fqdn"], cloud: ["cloud"] } + + separator = ui.presenter.attribute_field_separator + + # if we've set an attribute to use on the command line + if config[:attribute] + required_attributes[:config] = config[:attribute].split(separator) + end + + # if we've configured an attribute in our config + if Chef::Config[:knife][:ssh_attribute] + required_attributes[:knife_config] = Chef::Config[:knife][:ssh_attribute].split(separator) + end + + @search_count = 0 + query.search(:node, @name_args[0], filter_result: required_attributes) do |item| + @search_count += 1 # we should skip the loop to next iteration if the item # returned by the search is nil next if item.nil? # next if we couldn't find the specified attribute in the # returned node object - host = extract_nested_value(item, get_ssh_attribute(item)) + host = get_ssh_attribute(item) next if host.nil? ssh_port = item[:cloud].nil? ? nil : item[:cloud][:public_ssh_port] srv = [host, ssh_port] list.push(srv) end + list end @@ -232,7 +247,7 @@ class Chef # @param user [String] Optional username for this session. # @return [Hash<Symbol, Object>] def session_options(host, port, user = nil) - ssh_config = Net::SSH.configuration_for(host) + ssh_config = Net::SSH.configuration_for(host, true) {}.tap do |opts| # Chef::Config[:knife][:ssh_user] is parsed in #configure_user and written to config[:ssh_user] opts[:user] = user || config[:ssh_user] || ssh_config[:user] @@ -309,9 +324,9 @@ class Chef subsession ||= session command = fixup_sudo(command) command.force_encoding("binary") if command.respond_to?(:force_encoding) - subsession.open_channel do |ch| - ch.request_pty - ch.exec command do |ch, success| + subsession.open_channel do |chan| + chan.request_pty + chan.exec command do |ch, success| raise ArgumentError, "Cannot execute #{command}" unless success ch.on_data do |ichannel, data| print_data(ichannel[:host], data) @@ -532,10 +547,6 @@ class Chef config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file] || config[:identity_file] || Chef::Config[:knife][:ssh_identity_file]) end - def extract_nested_value(data_structure, path_spec) - ui.presenter.extract_nested_value(data_structure, path_spec) - end - def run @longest = 0 diff --git a/lib/chef/mixin/which.rb b/lib/chef/mixin/which.rb index 63c84883d5..4fa79eeccb 100644 --- a/lib/chef/mixin/which.rb +++ b/lib/chef/mixin/which.rb @@ -18,17 +18,13 @@ class Chef module Mixin module Which - def which(cmd, opts = {}) - extra_path = - if opts[:extra_path].nil? - [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ] - else - [ opts[:extra_path] ].flatten - end + def which(cmd, extra_path: nil) + # NOTE: unnecessarily duplicates function of path_sanity + extra_path ||= [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ] paths = ENV["PATH"].split(File::PATH_SEPARATOR) + extra_path paths.each do |path| - filename = File.join(path, cmd) - return filename if File.executable?(Chef.path_to(filename)) + filename = Chef.path_to(File.join(path, cmd)) + return filename if File.executable?(filename) end false end diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb index d2816d4824..0ee720daf4 100644 --- a/lib/chef/node/attribute.rb +++ b/lib/chef/node/attribute.rb @@ -416,23 +416,22 @@ class Chef def normal_unless(*args) return Decorator::Unchain.new(self, :normal_unless) unless args.length > 0 - write(:normal, *args) if read(*args[0...-1]).nil? + write(:normal, *args) if normal.read(*args[0...-1]).nil? end def default_unless(*args) return Decorator::Unchain.new(self, :default_unless) unless args.length > 0 - write(:default, *args) if read(*args[0...-1]).nil? + write(:default, *args) if default.read(*args[0...-1]).nil? end def override_unless(*args) return Decorator::Unchain.new(self, :override_unless) unless args.length > 0 - write(:override, *args) if read(*args[0...-1]).nil? + write(:override, *args) if override.read(*args[0...-1]).nil? end def set_unless(*args) Chef.deprecated(:attributes, "node.set_unless is deprecated and will be removed in Chef 14, please use node.default_unless/node.override_unless (or node.normal_unless if you really need persistence)") - return Decorator::Unchain.new(self, :default_unless) unless args.length > 0 - write(:normal, *args) if read(*args[0...-1]).nil? + normal_unless(*args) end def has_key?(key) diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb index 8d2437fef5..f0009eac6c 100644 --- a/lib/chef/policy_builder/policyfile.rb +++ b/lib/chef/policy_builder/policyfile.rb @@ -173,6 +173,7 @@ class Chef CookbookCacheCleaner.instance.skip_removal = true if named_run_list_requested? node.run_list(run_list) + node.automatic_attrs[:policy_revision] = revision_id node.automatic_attrs[:roles] = [] node.automatic_attrs[:recipes] = run_list_expansion_ish.recipes run_list_expansion_ish diff --git a/lib/chef/property.rb b/lib/chef/property.rb index 8d8ed352b3..8fa290251a 100644 --- a/lib/chef/property.rb +++ b/lib/chef/property.rb @@ -518,6 +518,13 @@ class Chef # be using the existing getter/setter to manipulate it instead. return if !instance_variable_name + # We deprecate any attempt to create a property that already exists as a + # method in some Classes that we know would cause our users problems. + # For example, creating a `hash` property could cause issues when adding + # a Chef::Resource instance to an data structure that expects to be able + # to call the `#hash` method and get back an appropriate Fixnum. + emit_property_redefinition_deprecations + # We prefer this form because the property name won't show up in the # stack trace if you use `define_method`. declared_in.class_eval <<-EOM, __FILE__, __LINE__ + 1 @@ -632,6 +639,30 @@ class Chef private + def emit_property_redefinition_deprecations + # We only emit deprecations if this property already exists as an instance method. + # Weeding out class methods avoids unnecessary deprecations such Chef::Resource + # defining a `name` property when there's an already-existing `name` method + # for a Module. + return unless declared_in.instance_methods.include?(name) + + # Only emit deprecations for some well-known classes. This will still + # allow more advanced users to subclass their own custom resources and + # override their own properties. + return unless [ Object, BasicObject, Kernel, Chef::Resource ].include?(declared_in.instance_method(name).owner) + + # Allow top-level Chef::Resource proprties, such as `name`, to be overridden. + # As of this writing, `name` is the only Chef::Resource property created with the + # `property` definition, but this will allow for future properties to be extended + # as needed. + return if Chef::Resource.properties.keys.include?(name) + + # Emit the deprecation. + resource_name = declared_in.respond_to?(:resource_name) ? declared_in.resource_name : declared_in + Chef.deprecated(:property_name_collision, "Property `#{name}` of resource `#{resource_name}` overwrites an existing method. " \ + "Please use a different property name. This will raise an exception in Chef 13.") + end + def exec_in_resource(resource, proc, *args) if resource if proc.arity > args.size diff --git a/lib/chef/provider/directory.rb b/lib/chef/provider/directory.rb index 619ab5d8b6..1cacc3fcb9 100644 --- a/lib/chef/provider/directory.rb +++ b/lib/chef/provider/directory.rb @@ -138,7 +138,7 @@ class Chef end do_acl_changes do_selinux(true) - load_resource_attributes_from_file(@new_resource) + load_resource_attributes_from_file(@new_resource) unless Chef::Config[:why_run] end def action_delete diff --git a/lib/chef/provider/dsc_resource.rb b/lib/chef/provider/dsc_resource.rb index 0f25065925..026d2ef104 100644 --- a/lib/chef/provider/dsc_resource.rb +++ b/lib/chef/provider/dsc_resource.rb @@ -29,6 +29,7 @@ class Chef super @new_resource = new_resource @module_name = new_resource.module_name + @module_version = new_resource.module_version @reboot_resource = nil end @@ -65,6 +66,13 @@ class Chef a.whyrun err + ["Assuming a previous resource sets the RefreshMode."] a.block_action! end + requirements.assert(:run) do |a| + a.assertion { module_usage_valid? } + err = ["module_name must be supplied along with module_version."] + a.failure_message Chef::Exceptions::DSCModuleNameMissing, + err + a.block_action! + end end protected @@ -92,6 +100,10 @@ class Chef Chef::Platform.supports_refresh_mode_enabled?(node) end + def module_usage_valid? + !(!@module_name && @module_version) + end + def generate_description @converge_description end @@ -148,10 +160,14 @@ class Chef end end + def module_info_object + @module_version.nil? ? module_name : "@{ModuleName='#{module_name}';ModuleVersion='#{@module_version}'}" + end + def invoke_resource(method, output_format = :object) properties = translate_type(@new_resource.properties) switches = "-Method #{method} -Name #{@new_resource.resource}"\ - " -Property #{properties} -Module #{module_name} -Verbose" + " -Property #{properties} -Module #{module_info_object} -Verbose" cmdlet = Chef::Util::Powershell::Cmdlet.new( node, "Invoke-DscResource #{switches}", diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb index 84bb4d1c94..f77986fa03 100644 --- a/lib/chef/provider/file.rb +++ b/lib/chef/provider/file.rb @@ -154,7 +154,7 @@ class Chef do_contents_changes do_acl_changes do_selinux - load_resource_attributes_from_file(@new_resource) + load_resource_attributes_from_file(@new_resource) unless Chef::Config[:why_run] end def action_create_if_missing diff --git a/lib/chef/provider/launchd.rb b/lib/chef/provider/launchd.rb index 0ec8d0cfe1..f3e0a00758 100644 --- a/lib/chef/provider/launchd.rb +++ b/lib/chef/provider/launchd.rb @@ -150,7 +150,7 @@ class Chef end def content - plist_hash = new_resource.hash || gen_hash + plist_hash = new_resource.plist_hash || gen_hash Plist::Emit.dump(plist_hash) unless plist_hash.nil? end diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index ecf3dbecb5..f52614672a 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -37,6 +37,9 @@ class Chef subclass_directive :use_multipackage_api # subclasses declare this if they want sources (filenames) pulled from their package names subclass_directive :use_package_name_for_source + # keeps package_names_for_targets and versions_for_targets indexed the same as package_name at + # the cost of having the subclass needing to deal with nils + subclass_directive :allow_nils # # Hook that subclasses use to populate the candidate_version(s) @@ -390,9 +393,12 @@ class Chef def package_names_for_targets package_names_for_targets = [] target_version_array.each_with_index do |target_version, i| - next if target_version.nil? - package_name = package_name_array[i] - package_names_for_targets.push(package_name) + if !target_version.nil? + package_name = package_name_array[i] + package_names_for_targets.push(package_name) + else + package_names_for_targets.push(nil) if allow_nils? + end end multipackage? ? package_names_for_targets : package_names_for_targets[0] end @@ -407,8 +413,11 @@ class Chef def versions_for_targets versions_for_targets = [] target_version_array.each_with_index do |target_version, i| - next if target_version.nil? - versions_for_targets.push(target_version) + if !target_version.nil? + versions_for_targets.push(target_version) + else + versions_for_targets.push(nil) if allow_nils? + end end multipackage? ? versions_for_targets : versions_for_targets[0] end diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb index 728f181055..12bf11ad0f 100644 --- a/lib/chef/provider/package/aix.rb +++ b/lib/chef/provider/package/aix.rb @@ -38,7 +38,7 @@ class Chef a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install" end requirements.assert(:all_actions) do |a| - a.assertion { !@new_resource.source || @package_source_found } + a.assertion { !@new_resource.source || package_source_found? } a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" a.whyrun "would assume #{@new_resource.source} would be have previously been made available" end @@ -48,24 +48,21 @@ class Chef @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) - if @new_resource.source - @package_source_found = ::File.exists?(@new_resource.source) - if @package_source_found - Chef::Log.debug("#{@new_resource} checking pkg status") - ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") - ret.stdout.each_line do |line| - case line - when /:#{@new_resource.package_name}:/ - fields = line.split(":") - @new_resource.version(fields[2]) - when /^#{@new_resource.package_name}:/ - Chef::Log.warn("You are installing a bff package by product name. For idempotent installs, please install individual filesets") - fields = line.split(":") - @new_resource.version(fields[2]) - end + if package_source_found? + Chef::Log.debug("#{@new_resource} checking pkg status") + ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") + ret.stdout.each_line do |line| + case line + when /:#{@new_resource.package_name}:/ + fields = line.split(":") + @new_resource.version(fields[2]) + when /^#{@new_resource.package_name}:/ + Chef::Log.warn("You are installing a bff package by product name. For idempotent installs, please install individual filesets") + fields = line.split(":") + @new_resource.version(fields[2]) end - raise Chef::Exceptions::Package, "package source #{@new_resource.source} does not provide package #{@new_resource.package_name}" unless @new_resource.version end + raise Chef::Exceptions::Package, "package source #{@new_resource.source} does not provide package #{@new_resource.package_name}" unless @new_resource.version end Chef::Log.debug("#{@new_resource} checking install state") @@ -88,18 +85,20 @@ class Chef def candidate_version return @candidate_version if @candidate_version - ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") - ret.stdout.each_line do |line| - case line - when /\w:#{Regexp.escape(@new_resource.package_name)}:(.*)/ - fields = line.split(":") - @candidate_version = fields[2] - @new_resource.version(fields[2]) - Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}") + if package_source_found? + ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") + ret.stdout.each_line do |line| + case line + when /\w:#{Regexp.escape(@new_resource.package_name)}:(.*)/ + fields = line.split(":") + @candidate_version = fields[2] + @new_resource.version(fields[2]) + Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}") + end + end + unless ret.exitstatus == 0 + raise Chef::Exceptions::Package, "installp -L -d #{@new_resource.source} - #{ret.format_for_exception}!" end - end - unless ret.exitstatus == 0 - raise Chef::Exceptions::Package, "installp -L -d #{@new_resource.source} - #{ret.format_for_exception}!" end @candidate_version end @@ -134,6 +133,10 @@ class Chef end end + def package_source_found? + @package_source_found ||= @new_resource.source && ::File.exists?(@new_resource.source) + end + end end end diff --git a/lib/chef/provider/package/cab.rb b/lib/chef/provider/package/cab.rb index 8e1709f618..a281100f8b 100644 --- a/lib/chef/provider/package/cab.rb +++ b/lib/chef/provider/package/cab.rb @@ -19,29 +19,59 @@ require "chef/provider/package" require "chef/resource/cab_package" require "chef/mixin/shell_out" +require "chef/mixin/uris" +require "chef/mixin/checksum" class Chef class Provider class Package class Cab < Chef::Provider::Package + use_inline_resources include Chef::Mixin::ShellOut + include Chef::Mixin::Uris + include Chef::Mixin::Checksum provides :cab_package, os: "windows" def load_current_resource @current_resource = Chef::Resource::CabPackage.new(new_resource.name) - current_resource.source(new_resource.source) + current_resource.source(cab_file_source) new_resource.version(package_version) current_resource.version(installed_version) current_resource end + def cab_file_source + @cab_file_source ||= uri_scheme?(new_resource.source) ? download_source_file : new_resource.source + end + + def download_source_file + source_resource.run_action(:create) + Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}") + source_resource.path + end + + def source_resource + @source_resource ||= declare_resource(:remote_file, new_resource.name) do + path default_download_cache_path + source new_resource.source + backup false + end + end + + def default_download_cache_path + uri = ::URI.parse(new_resource.source) + filename = ::File.basename(::URI.unescape(uri.path)) + file_cache_dir = Chef::FileCache.create_cache_path("package/") + Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}") + end + def install_package(name, version) - dism_command("/Add-Package /PackagePath:\"#{@new_resource.source}\"") + dism_command("/Add-Package /PackagePath:\"#{cab_file_source}\"") end def remove_package(name, version) - dism_command("/Remove-Package /PackagePath:\"#{@new_resource.source}\"") + dism_command("/Remove-Package /PackagePath:\"#{cab_file_source}\"") end def dism_command(command) @@ -52,7 +82,7 @@ class Chef end def installed_version - stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{@new_resource.source}\"").stdout + stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{cab_file_source}\"").stdout package_info = parse_dism_get_package_info(stdout) # e.g. Package_for_KB2975719~31bf3856ad364e35~amd64~~6.3.1.8 package = split_package_identity(package_info["package_information"]["package_identity"]) @@ -71,8 +101,8 @@ class Chef end def package_version - Chef::Log.debug("#{@new_resource} getting product version for package at #{@new_resource.source}") - stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{@new_resource.source}\"").stdout + Chef::Log.debug("#{@new_resource} getting product version for package at #{cab_file_source}") + stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{cab_file_source}\"").stdout find_version(stdout) end diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb index 90624b9a0b..02a196fa8c 100644 --- a/lib/chef/provider/package/chocolatey.rb +++ b/lib/chef/provider/package/chocolatey.rb @@ -169,7 +169,7 @@ EOS # @param args [String] variable number of string arguments # @return [Mixlib::ShellOut] object returned from shell_out! def choco_command(*args) - shell_out_with_timeout!(args_to_string(choco_exe, *args)) + shell_out_with_timeout!(args_to_string(choco_exe, *args), { :returns => new_resource.returns }) end # Use the available_packages Hash helper to create an array suitable for @@ -236,6 +236,7 @@ EOS available[name] = desired_name_versions[name] || raw[name] end end + @available_packages end # Installed packages in chocolatey as a Hash of names mapped to versions @@ -244,6 +245,7 @@ EOS # @return [Hash] name-to-version mapping of installed packages def installed_packages @installed_packages ||= Hash[*parse_list_output("list -l -r").flatten] + @installed_packages end # Helper to convert choco.exe list output to a Hash diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb new file mode 100644 index 0000000000..bf6aa2438f --- /dev/null +++ b/lib/chef/provider/package/dnf.rb @@ -0,0 +1,183 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "chef/provider/package" +require "chef/resource/dnf_package" +require "chef/mixin/which" +require "chef/mixin/get_source_from_package" +require "chef/provider/package/dnf/python_helper" +require "chef/provider/package/dnf/version" + +class Chef + class Provider + class Package + class Dnf < Chef::Provider::Package + extend Chef::Mixin::Which + include Chef::Mixin::GetSourceFromPackage + + allow_nils + use_multipackage_api + use_package_name_for_source + + provides :package, platform_family: %w{rhel fedora} do + which("dnf") + end + + provides :dnf_package, os: "linux" + + # + # Most of the magic in this class happens in the python helper script. The ruby side of this + # provider knows only enough to translate Chef-style new_resource name+package+version into + # a request to the python side. The python side is then responsible for knowing everything + # about RPMs and what is installed and what is available. The ruby side of this class should + # remain a lightweight translation layer to translate Chef requests into RPC requests to + # python. This class knows nothing about how to compare RPM versions, and does not maintain + # any cached state of installed/available versions and should be kept that way. + # + def python_helper + @python_helper ||= PythonHelper.instance + end + + def load_current_resource + flushcache if new_resource.flush_cache[:before] + + @current_resource = Chef::Resource::DnfPackage.new(new_resource.name) + current_resource.package_name(new_resource.package_name) + current_resource.version(get_current_versions) + + current_resource + end + + def define_resource_requirements + requirements.assert(:install, :upgrade, :remove, :purge) do |a| + a.assertion { !new_resource.source || ::File.exist?(new_resource.source) } + a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}" + a.whyrun "assuming #{new_resource.source} would have previously been created" + end + + super + end + + def candidate_version + package_name_array.each_with_index.map do |pkg, i| + available_version(i).version_with_arch + end + end + + def get_current_versions + package_name_array.each_with_index.map do |pkg, i| + installed_version(i).version_with_arch + end + end + + def install_package(names, versions) + if new_resource.source + dnf(new_resource.options, "-y install", new_resource.source) + else + resolved_names = names.each_with_index.map { |name, i| available_version(i).to_s unless name.nil? } + dnf(new_resource.options, "-y install", resolved_names) + end + flushcache + end + + # dnf upgrade does not work on uninstalled packaged, while install will upgrade + alias_method :upgrade_package, :install_package + + def remove_package(names, versions) + resolved_names = names.each_with_index.map { |name, i| installed_version(i).to_s unless name.nil? } + dnf(new_resource.options, "-y remove", resolved_names) + flushcache + end + + alias_method :purge_package, :remove_package + + action :flush_cache do + flushcache + end + + private + + def resolve_source_to_version_obj + shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line| + # this is another case of committing the sin of doing some lightweight mangling of RPM versions in ruby -- but the output of the rpm command + # does not match what the dnf library accepts. + case line + when /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/ + return Version.new($1, "#{$2 == "(none)" ? "0" : $2}:#{$3}-#{$4}", $5) + end + end + end + + # @returns Array<Version> + def available_version(index) + @available_version ||= [] + + if new_resource.source + @available_version[index] ||= resolve_source_to_version_obj + else + @available_version[index] ||= python_helper.query(:whatavailable, package_name_array[index], safe_version_array[index], safe_arch_array[index]) + end + + @available_version[index] + end + + # @returns Array<Version> + def installed_version(index) + @installed_version ||= [] + if new_resource.source + @installed_version[index] ||= python_helper.query(:whatinstalled, available_version(index).name, safe_version_array[index], safe_arch_array[index]) + else + @installed_version[index] ||= python_helper.query(:whatinstalled, package_name_array[index], safe_version_array[index], safe_arch_array[index]) + end + @installed_version[index] + end + + # cache flushing is accomplished by simply restarting the python helper. this produces a roughly + # 15% hit to the runtime of installing/removing/upgrading packages. correctly using multipackage + # array installs (and the multipackage cookbook) can produce 600% improvements in runtime. + def flushcache + python_helper.restart + end + + def dnf(*args) + shell_out_with_timeout!(a_to_s("dnf", *args)) + end + + def safe_version_array + if new_resource.version.is_a?(Array) + new_resource.version + elsif new_resource.version.nil? + package_name_array.map { nil } + else + [ new_resource.version ] + end + end + + def safe_arch_array + if new_resource.arch.is_a?(Array) + new_resource.arch + elsif new_resource.arch.nil? + package_name_array.map { nil } + else + [ new_resource.arch ] + end + end + + end + end + end +end diff --git a/lib/chef/provider/package/dnf/dnf_helper.py b/lib/chef/provider/package/dnf/dnf_helper.py new file mode 100644 index 0000000000..236b967710 --- /dev/null +++ b/lib/chef/provider/package/dnf/dnf_helper.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 + +import sys +import dnf +import hawkey +import signal +import os +import json + +base = None + +def get_sack(): + global base + if base is None: + base = dnf.Base() + base.read_all_repos() + base.fill_sack() + return base.sack + +# FIXME: leaks memory and does not work +def flushcache(): + try: + os.remove('/var/cache/dnf/@System.solv') + except OSError: + pass + get_sack().load_system_repo(build_cache=True) + +def query(command): + sack = get_sack() + + subj = dnf.subject.Subject(command['provides']) + q = subj.get_best_query(sack, with_provides=True) + + if command['action'] == "whatinstalled": + q = q.installed() + + if command['action'] == "whatavailable": + q = q.available() + + if 'epoch' in command: + q = q.filterm(epoch=int(command['epoch'])) + if 'version' in command: + q = q.filterm(version__glob=command['version']) + if 'release' in command: + q = q.filterm(release__glob=command['release']) + + if 'arch' in command: + q = q.filterm(arch__glob=command['arch']) + + # only apply the default arch query filter if it returns something + archq = q.filter(arch=[ 'noarch', hawkey.detect_arch() ]) + if len(archq.run()) > 0: + q = archq + + pkgs = dnf.query.latest_limit_pkgs(q, 1) + + if not pkgs: + sys.stdout.write('{} nil nil\n'.format(command['provides'].split().pop(0))) + else: + # make sure we picked the package with the highest version + pkgs.sort + pkg = pkgs.pop() + sys.stdout.write('{} {}:{}-{} {}\n'.format(pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch)) + +# the design of this helper is that it should try to be 'brittle' and fail hard and exit in order +# to keep process tables clean. additional error handling should probably be added to the retry loop +# on the ruby side. +def exit_handler(signal, frame): + sys.exit(0) + +signal.signal(signal.SIGINT, exit_handler) +signal.signal(signal.SIGHUP, exit_handler) +signal.signal(signal.SIGPIPE, exit_handler) +signal.signal(signal.SIGCHLD, exit_handler) + +while 1: + # kill self if we get orphaned (tragic) + ppid = os.getppid() + if ppid == 1: + sys.exit(0) + line = sys.stdin.readline() + command = json.loads(line) + if command['action'] == "whatinstalled": + query(command) + elif command['action'] == "whatavailable": + query(command) + elif command['action'] == "flushcache": + flushcache() + else: + raise RuntimeError("bad command") diff --git a/lib/chef/provider/package/dnf/python_helper.rb b/lib/chef/provider/package/dnf/python_helper.rb new file mode 100644 index 0000000000..466114b339 --- /dev/null +++ b/lib/chef/provider/package/dnf/python_helper.rb @@ -0,0 +1,120 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "chef/provider/package/dnf/version" +require "timeout" + +class Chef + class Provider + class Package + class Dnf < Chef::Provider::Package + class PythonHelper + include Singleton + extend Chef::Mixin::Which + + attr_accessor :stdin + attr_accessor :stdout + attr_accessor :stderr + attr_accessor :wait_thr + + DNF_HELPER = ::File.expand_path(::File.join(::File.dirname(__FILE__), "dnf_helper.py")).freeze + DNF_COMMAND = "#{which("python3")} #{DNF_HELPER}" + + def start + ENV["PYTHONUNBUFFERED"] = "1" + @stdin, @stdout, @stderr, @wait_thr = Open3.popen3(DNF_COMMAND) + end + + def reap + unless wait_thr.nil? + Process.kill("KILL", wait_thr.pid) rescue nil + stdin.close unless stdin.nil? + stdout.close unless stdout.nil? + stderr.close unless stderr.nil? + wait_thr.value # this calls waitpit() + end + end + + def check + start if stdin.nil? + end + + # i couldn't figure out how to decompose an evr on the python side, it seems reasonably + # painless to do it in ruby (generally massaging nevras in the ruby side is HIGHLY + # discouraged -- this is an "every rule has an exception" exception -- any additional + # functionality should probably trigger moving this regexp logic into python) + def add_version(hash, version) + epoch = nil + if version =~ /(\S+):(\S+)/ + epoch, version = $1, $2 + end + if version =~ /(\S+)-(\S+)/ + version, release = $1, $2 + end + hash["epoch"] = epoch unless epoch.nil? + hash["release"] = release unless release.nil? + hash["version"] = version + end + + def build_query(action, provides, version, arch) + hash = { "action" => action } + hash["provides"] = provides + add_version(hash, version) unless version.nil? + hash["arch" ] = arch unless arch.nil? + FFI_Yajl::Encoder.encode(hash) + end + + def parse_response(output) + array = output.split.map { |x| x == "nil" ? nil : x } + array.each_slice(3).map { |x| Version.new(*x) }.first + end + + # @returns Array<Version> + def query(action, provides, version = nil, arch = nil) + with_helper do + json = build_query(action, provides, version, arch) + Chef::Log.debug "sending '#{json}' to python helper" + stdin.syswrite json + "\n" + output = stdout.sysread(4096).chomp + Chef::Log.debug "got '#{output}' from python helper" + version = parse_response(output) + Chef::Log.debug "parsed #{version} from python helper" + version + end + end + + def restart + reap + start + end + + def with_helper + max_retries ||= 5 + Timeout.timeout(600) do + check + yield + end + rescue EOFError, Errno::EPIPE, Timeout::Error, Errno::ESRCH => e + raise e unless ( max_retries -= 1 ) > 0 + restart + retry + end + end + end + end + end +end diff --git a/lib/chef/provider/package/dnf/version.rb b/lib/chef/provider/package/dnf/version.rb new file mode 100644 index 0000000000..b326913c3a --- /dev/null +++ b/lib/chef/provider/package/dnf/version.rb @@ -0,0 +1,56 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + class Provider + class Package + class Dnf < Chef::Provider::Package + + # helper class to assist in passing around name/version/arch triples + class Version + attr_accessor :name + attr_accessor :version + attr_accessor :arch + + def initialize(name, version, arch) + @name = name + @version = version + @arch = arch + end + + def to_s + "#{name}-#{version}.#{arch}" + end + + def version_with_arch + "#{version}.#{arch}" unless version.nil? + end + + def matches_name_and_arch?(other) + other.version == version && other.arch == arch + end + + def ==(other) + name == other.name && version == other.version && arch == other.arch + end + + alias_method :eql?, :== + end + end + end + end +end diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb index f2b7b33419..5e20fdf11e 100644 --- a/lib/chef/provider/route.rb +++ b/lib/chef/provider/route.rb @@ -219,7 +219,7 @@ class Chef case action when :add content << (options[:target]).to_s - content << "/#{options[:netmask]}" if options[:netmask] + content << "/#{MASK[options[:netmask].to_s]}" if options[:netmask] content << " via #{options[:gateway]}" if options[:gateway] content << "\n" end diff --git a/lib/chef/provider/support/yum_repo.erb b/lib/chef/provider/support/yum_repo.erb index 7d9a2d09e2..6f1325573d 100644 --- a/lib/chef/provider/support/yum_repo.erb +++ b/lib/chef/provider/support/yum_repo.erb @@ -4,8 +4,13 @@ [<%= @config.repositoryid %>] name=<%= @config.description %> <% if @config.baseurl %> -baseurl=<%= @config.baseurl %> -<% end %> +baseurl=<%= case @config.baseurl + when Array + @config.baseurl.join("\n") + else + @config.baseurl + end %> +<% end -%> <% if @config.cost %> cost=<%= @config.cost %> <% end %> @@ -24,7 +29,9 @@ exclude=<%= @config.exclude %> failovermethod=<%= @config.failovermethod %> <% end %> <% if @config.fastestmirror_enabled %> -fastestmirror_enabled=<%= @config.fastestmirror_enabled %> +fastestmirror_enabled=1 +<% else %> +fastestmirror_enabled=0 <% end %> <% if @config.gpgcheck %> gpgcheck=1 diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb index ebb4c45ae8..35722840e6 100644 --- a/lib/chef/providers.rb +++ b/lib/chef/providers.rb @@ -65,6 +65,7 @@ require "chef/provider/env/windows" require "chef/provider/package/apt" require "chef/provider/package/chocolatey" require "chef/provider/package/dpkg" +require "chef/provider/package/dnf" require "chef/provider/package/easy_install" require "chef/provider/package/freebsd/port" require "chef/provider/package/freebsd/pkg" diff --git a/lib/chef/resource/apt_repository.rb b/lib/chef/resource/apt_repository.rb index 8b87371824..b38bd1c8ec 100644 --- a/lib/chef/resource/apt_repository.rb +++ b/lib/chef/resource/apt_repository.rb @@ -38,7 +38,6 @@ class Chef property :cookbook, [String, nil, false], default: nil, desired_state: false, nillable: true, coerce: proc { |x| x ? x : nil } property :cache_rebuild, [TrueClass, FalseClass], default: true, desired_state: false - property :sensitive, [TrueClass, FalseClass], default: false, desired_state: false default_action :add allowed_actions :add, :remove diff --git a/lib/chef/resource/chocolatey_package.rb b/lib/chef/resource/chocolatey_package.rb index 805d3a3121..5460661f6d 100644 --- a/lib/chef/resource/chocolatey_package.rb +++ b/lib/chef/resource/chocolatey_package.rb @@ -34,6 +34,7 @@ class Chef property :package_name, [String, Array], coerce: proc { |x| [x].flatten } property :version, [String, Array], coerce: proc { |x| [x].flatten } + property :returns, [Integer, Array], default: [ 0 ], desired_state: false end end end diff --git a/lib/chef/resource/dnf_package.rb b/lib/chef/resource/dnf_package.rb new file mode 100644 index 0000000000..92f7532fc2 --- /dev/null +++ b/lib/chef/resource/dnf_package.rb @@ -0,0 +1,64 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "chef/resource/package" + +class Chef + class Resource + class DnfPackage < Chef::Resource::Package + extend Chef::Mixin::Which + + resource_name :dnf_package + + allowed_actions :install, :upgrade, :remove, :purge, :reconfig, :lock, :unlock, :flush_cache + + provides :package, os: "linux", platform_family: %w{rhel fedora} do + which("dnf") + end + + provides :dnf_package + + # Install a specific arch + property :arch, [String, Array], coerce: proc { |x| [x].flatten } + + # Flush the in-memory available/installed cache, this does not flush the dnf caches on disk + property :flush_cache, + Hash, + default: { before: false, after: false }, + coerce: proc { |v| + if v.is_a?(Hash) + v + elsif v.is_a?(Array) + v.each_with_object({}) { |arg, obj| obj[arg] = true } + elsif v.is_a?(TrueClass) || v.is_a?(FalseClass) + { before: v, after: v } + elsif v == :before + { before: true, after: false } + elsif v == :after + { after: true, before: false } + end + } + + def allow_downgrade(arg = nil) + if !arg.nil? + Chef.deprecated(:dnf_package_allow_downgrade, "the allow_downgrade property on the dnf_package provider is not used, DNF supports downgrades by default.") + end + false + end + end + end +end diff --git a/lib/chef/resource/dsc_resource.rb b/lib/chef/resource/dsc_resource.rb index 58594cce7b..f55f8d2c8c 100644 --- a/lib/chef/resource/dsc_resource.rb +++ b/lib/chef/resource/dsc_resource.rb @@ -68,6 +68,14 @@ class Chef end end + def module_version(arg = nil) + set_or_return( + :module_version, + arg, + :kind_of => [ String ] + ) + end + def property(property_name, value = nil) if not property_name.is_a?(Symbol) raise TypeError, "A property name of type Symbol must be specified, '#{property_name}' of type #{property_name.class} was given" diff --git a/lib/chef/resource/launchd.rb b/lib/chef/resource/launchd.rb index 6427b13f84..c78ffa3f0e 100644 --- a/lib/chef/resource/launchd.rb +++ b/lib/chef/resource/launchd.rb @@ -33,7 +33,7 @@ class Chef property :backup, [Integer, FalseClass] property :cookbook, String property :group, [String, Integer] - property :hash, Hash + property :plist_hash, Hash property :mode, [String, Integer] property :owner, [String, Integer] property :path, String @@ -139,6 +139,18 @@ class Chef property :wait_for_debugger, [ TrueClass, FalseClass ] property :watch_paths, Array property :working_directory, String + + # hash is an instance method on Object and needs to return a Fixnum. + def hash(arg = nil) + Chef.deprecated(:launchd_hash_property, "Property `hash` on the `launchd` resource has changed to `plist_hash`." \ + "Please use `plist_hash` instead. This will raise an exception in Chef 13.") + + set_or_return( + :plist_hash, + arg, + :kind_of => Hash + ) + end end end end diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb index 9d69897f5f..1e0ad197ba 100644 --- a/lib/chef/resource/yum_package.rb +++ b/lib/chef/resource/yum_package.rb @@ -17,7 +17,6 @@ # require "chef/resource/package" -require "chef/provider/package/yum" class Chef class Resource @@ -27,22 +26,27 @@ class Chef # Install a specific arch property :arch, [ String, Array ] - # the {} on the proc here is because rspec chokes if it's do...end + property :flush_cache, - Hash, - default: { before: false, after: false }, - coerce: proc { |v| - if v.is_a?(Array) - v.each_with_object({}) { |arg, obj| obj[arg] = true } - elsif v.any? - v - else - { before: v, after: v } - end - } + Hash, + default: { before: false, after: false }, + coerce: proc { |v| + if v.is_a?(Hash) + v + elsif v.is_a?(Array) + v.each_with_object({}) { |arg, obj| obj[arg] = true } + elsif v.is_a?(TrueClass) || v.is_a?(FalseClass) + { before: v, after: v } + elsif v == :before + { before: true, after: false } + elsif v == :after + { after: true, before: false } + end + } + property :allow_downgrade, [ true, false ], default: false - property :yum_binary, String + property :yum_binary, String end end end diff --git a/lib/chef/resource/yum_repository.rb b/lib/chef/resource/yum_repository.rb index 1c215b51ff..f59ad56d16 100644 --- a/lib/chef/resource/yum_repository.rb +++ b/lib/chef/resource/yum_repository.rb @@ -25,7 +25,7 @@ class Chef provides :yum_repository # http://linux.die.net/man/5/yum.conf - property :baseurl, String, regex: /.*/ + property :baseurl, [String, Array], regex: /.*/ property :cost, String, regex: /^\d+$/ property :clean_headers, [TrueClass, FalseClass], default: false # deprecated property :clean_metadata, [TrueClass, FalseClass], default: true @@ -58,7 +58,6 @@ class Chef property :repo_gpgcheck, [TrueClass, FalseClass] property :report_instanceid, [TrueClass, FalseClass] property :repositoryid, String, regex: /.*/, name_property: true - property :sensitive, [TrueClass, FalseClass], default: false property :skip_if_unavailable, [TrueClass, FalseClass] property :source, String, regex: /.*/ property :sslcacert, String, regex: /.*/ diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb index de421839e0..ab89ce66e0 100644 --- a/lib/chef/resources.rb +++ b/lib/chef/resources.rb @@ -31,6 +31,7 @@ require "chef/resource/deploy" require "chef/resource/deploy_revision" require "chef/resource/directory" require "chef/resource/dpkg_package" +require "chef/resource/dnf_package" require "chef/resource/dsc_script" require "chef/resource/dsc_resource" require "chef/resource/easy_install_package" diff --git a/lib/chef/version.rb b/lib/chef/version.rb index be07504969..e727be6fa3 100644 --- a/lib/chef/version.rb +++ b/lib/chef/version.rb @@ -21,7 +21,7 @@ class Chef CHEF_ROOT = File.expand_path("../..", __FILE__) - VERSION = "12.18.19" + VERSION = "12.19.4" end # diff --git a/lib/chef/win32/security.rb b/lib/chef/win32/security.rb index 8bf2bfa762..c7d3f55a40 100644 --- a/lib/chef/win32/security.rb +++ b/lib/chef/win32/security.rb @@ -239,7 +239,7 @@ class Chef security_descriptor = FFI::MemoryPointer.new :pointer hr = GetNamedSecurityInfoW(path.to_wstring, type, info, nil, nil, nil, nil, security_descriptor) if hr != ERROR_SUCCESS - Chef::ReservedNames::Win32::Error.raise!("get_named_security_info(#{path}, #{type}, #{info})") + Chef::ReservedNames::Win32::Error.raise!("get_named_security_info(#{path}, #{type}, #{info})", hr) end result_pointer = security_descriptor.read_pointer @@ -538,7 +538,7 @@ class Chef hr = SetNamedSecurityInfoW(path.to_wstring, type, security_information, owner, group, dacl, sacl) if hr != ERROR_SUCCESS - Chef::ReservedNames::Win32::Error.raise! + Chef::ReservedNames::Win32::Error.raise! nil, hr end end diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock index e64c4659b4..a60b85d84a 100644 --- a/omnibus/Gemfile.lock +++ b/omnibus/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: git://github.com/chef/license_scout.git - revision: 95a308e01848e7843c84fa9be6214fa06e30f436 + revision: 383ad28edeea0f587aee57b969c77a21b7909e77 specs: license_scout (0.1.2) ffi-yajl (~> 2.2) @@ -8,7 +8,7 @@ GIT GIT remote: git://github.com/chef/omnibus-software.git - revision: cd69f8563fa8875c82a4e44652ffbfdac7ef201d + revision: 086710002ec0054b3d240d14ca04d11163f528aa branch: shain/ruby_windows_monster specs: omnibus-software (4.0.0) @@ -17,7 +17,7 @@ GIT GIT remote: git://github.com/chef/omnibus.git - revision: 0612bf6333b2a7b125e599228ec6c46cbaa3ed3d + revision: dce5283a85a44484a66a8a84991beba92e46fd12 branch: rhass/COOL-502_with_gcc_investigate specs: omnibus (5.5.0) @@ -35,15 +35,18 @@ GIT GEM remote: https://rubygems.org/ specs: - addressable (2.4.0) - artifactory (2.5.0) + addressable (2.5.0) + public_suffix (~> 2.0, >= 2.0.2) + artifactory (2.5.1) awesome_print (1.7.0) - aws-sdk (2.6.18) - aws-sdk-resources (= 2.6.18) - aws-sdk-core (2.6.18) + aws-sdk (2.7.0) + aws-sdk-resources (= 2.7.0) + aws-sdk-core (2.7.0) + aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.6.18) - aws-sdk-core (= 2.6.18) + aws-sdk-resources (2.7.0) + aws-sdk-core (= 2.7.0) + aws-sigv4 (1.0.0) berkshelf (4.3.5) addressable (~> 2.3, >= 2.3.4) berkshelf-api-client (~> 2.0, >= 2.0.2) @@ -76,14 +79,14 @@ GEM buff-ruby_engine (0.1.0) buff-shell_out (0.2.0) buff-ruby_engine (~> 0.1.0) - builder (3.2.2) + builder (3.2.3) byebug (9.0.6) celluloid (0.16.0) timers (~> 4.0.0) celluloid-io (0.16.2) celluloid (>= 0.16.0) nio4r (>= 1.1.0) - chef-config (12.15.19) + chef-config (12.18.31) addressable fuzzyurl mixlib-config (~> 2.0) @@ -95,8 +98,8 @@ GEM erubis (2.7.0) faraday (0.9.2) multipart-post (>= 1.2, < 3) - ffi (1.9.14) - ffi (1.9.14-x86-mingw32) + ffi (1.9.17) + ffi (1.9.17-x86-mingw32) ffi-yajl (2.3.0) libyajl2 (~> 1.2) fuzzyurl (0.9.0) @@ -111,7 +114,7 @@ GEM iostruct (0.0.4) ipaddress (0.8.3) jmespath (1.3.1) - json (2.0.2) + json (2.0.3) kitchen-vagrant (0.19.0) test-kitchen (~> 1.4) libyajl2 (1.2.0) @@ -121,13 +124,13 @@ GEM multi_json (~> 1.10) method_source (0.8.2) minitar (0.5.4) - mixlib-archive (0.2.0) + mixlib-archive (0.3.0) mixlib-log mixlib-authentication (1.4.1) mixlib-log mixlib-cli (1.7.0) mixlib-config (2.2.4) - mixlib-install (2.1.6) + mixlib-install (2.1.10) artifactory mixlib-shellout mixlib-versioning @@ -143,14 +146,14 @@ GEM multipart-post (2.0.0) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (3.2.0) + net-ssh (4.0.1) net-ssh-gateway (1.2.0) net-ssh (>= 2.6.5) - nio4r (1.2.1) + nio4r (2.0.0) nori (2.6.0) - octokit (4.4.1) - sawyer (~> 0.7.0, >= 0.5.3) - ohai (8.21.0) + octokit (4.6.2) + sawyer (~> 0.8.0, >= 0.5.3) + ohai (8.22.1) chef-config (>= 12.5.0.alpha.1, < 13) ffi (~> 1.9) ffi-yajl (~> 2.2) @@ -169,17 +172,18 @@ GEM progressbar zhexdump (>= 0.0.2) plist (3.2.0) - progressbar (0.21.0) + progressbar (1.8.2) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - pry-byebug (3.4.0) + pry-byebug (3.4.2) byebug (~> 9.0) pry (~> 0.10) pry-stack_explorer (0.4.9.2) binding_of_caller (>= 0.7) pry (>= 0.9.11) + public_suffix (2.0.5) retryable (2.0.4) ridley (4.6.1) addressable @@ -203,24 +207,24 @@ GEM rubyntlm (0.6.1) rubyzip (1.2.0) safe_yaml (1.0.4) - sawyer (0.7.0) - addressable (>= 2.3.5, < 2.5) - faraday (~> 0.8, < 0.10) + sawyer (0.8.1) + addressable (>= 2.3.5, < 2.6) + faraday (~> 0.8, < 1.0) semverse (1.2.1) slop (3.6.0) solve (2.0.3) molinillo (~> 0.4.2) semverse (~> 1.1) systemu (2.6.5) - test-kitchen (1.13.2) + test-kitchen (1.15.0) mixlib-install (>= 1.2, < 3.0) mixlib-shellout (>= 1.2, < 3.0) net-scp (~> 1.1) - net-ssh (>= 2.9, < 4.0) - net-ssh-gateway (~> 1.2.0) + net-ssh (>= 2.9, < 5.0) + net-ssh-gateway (~> 1.2) safe_yaml (~> 1.0) thor (~> 0.18) - thor (0.19.1) + thor (0.19.4) timers (4.0.4) hitimes varia_model (0.4.1) @@ -228,7 +232,7 @@ GEM hashie (>= 2.0.2, < 4.0.0) win32-process (0.8.3) ffi (>= 1.0.0) - winrm (2.1.0) + winrm (2.1.2) builder (>= 2.1.2) erubis (~> 2.7) gssapi (~> 1.2) @@ -237,7 +241,7 @@ GEM logging (>= 1.6.1, < 3.0) nori (~> 2.0) rubyntlm (~> 0.6.0, >= 0.6.1) - winrm-fs (1.0.0) + winrm-fs (1.0.1) erubis (~> 2.7) logging (>= 1.6.1, < 3.0) rubyzip (~> 1.1) diff --git a/omnibus/config/projects/chef.rb b/omnibus/config/projects/chef.rb index 3d92d290a0..a0e490ceab 100644 --- a/omnibus/config/projects/chef.rb +++ b/omnibus/config/projects/chef.rb @@ -39,11 +39,6 @@ else install_dir "#{default_root}/#{name}" end -# Global FIPS override flag. -if windows? || rhel? - override :fips, enabled: true -end - # Load dynamically updated overrides overrides_path = File.expand_path("../../../../omnibus_overrides.rb", current_file) instance_eval(IO.read(overrides_path), overrides_path) diff --git a/omnibus/config/software/chef-gem-bcrypt_pbkdf-ruby.rb b/omnibus/config/software/chef-gem-bcrypt_pbkdf-ruby.rb new file mode 100644 index 0000000000..1f7f4d3207 --- /dev/null +++ b/omnibus/config/software/chef-gem-bcrypt_pbkdf-ruby.rb @@ -0,0 +1,10 @@ +# gem installs this gem from the version specified in chef's Gemfile.lock +# so we can take advantage of omnibus's caching. Just duplicate this file and +# add the new software def to chef software def if you want to separate +# another gem's installation. +require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def" +BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__) + +license "MIT" +license_file "https://raw.githubusercontent.com/mfazekas/bcrypt_pbkdf-ruby/master/COPYING" +skip_transitive_dependency_licensing true diff --git a/omnibus/config/software/chef-gem-rbnacl-libsodium.rb b/omnibus/config/software/chef-gem-rbnacl-libsodium.rb new file mode 100644 index 0000000000..90bbc69dfb --- /dev/null +++ b/omnibus/config/software/chef-gem-rbnacl-libsodium.rb @@ -0,0 +1,10 @@ +# gem installs this gem from the version specified in chef's Gemfile.lock +# so we can take advantage of omnibus's caching. Just duplicate this file and +# add the new software def to chef software def if you want to separate +# another gem's installation. +require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def" +BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__) + +license "MIT" +license_file "https://raw.githubusercontent.com/cryptosphere/rbnacl-libsodium/master/LICENSE" +skip_transitive_dependency_licensing true diff --git a/omnibus/config/software/chef.rb b/omnibus/config/software/chef.rb index c6ced7e566..c53a2339ae 100644 --- a/omnibus/config/software/chef.rb +++ b/omnibus/config/software/chef.rb @@ -44,6 +44,10 @@ dependency "chef-gem-ruby-prof" dependency "chef-gem-byebug" dependency "chef-gem-debug_inspector" dependency "chef-gem-binding_of_caller" +unless ios_xr? || solaris? + dependency "chef-gem-rbnacl-libsodium" + dependency "chef-gem-bcrypt_pbkdf-ruby" +end # Now everyone else, in alphabetical order because we don't care THAT much Dir.entries(File.dirname(__FILE__)).sort.each do |gem_software| diff --git a/omnibus/omnibus.rb b/omnibus/omnibus.rb index c6f883adbc..dfbd2bc338 100644 --- a/omnibus/omnibus.rb +++ b/omnibus/omnibus.rb @@ -52,3 +52,4 @@ fetcher_read_timeout 120 # local_software_dirs ['/path/to/local/software'] fatal_transitive_dependency_licensing_warnings true +fips_mode (ENV["OMNIBUS_FIPS_MODE"] || "").casecmp("true") >= 0 diff --git a/omnibus_overrides.rb b/omnibus_overrides.rb index 0d740ff046..69af8dbd44 100644 --- a/omnibus_overrides.rb +++ b/omnibus_overrides.rb @@ -1,6 +1,7 @@ # DO NOT EDIT. Generated by "rake dependencies". Edit version_policy.rb instead. -override :rubygems, version: "2.6.8" +override :rubygems, version: "2.6.10" override :bundler, version: "1.12.5" +override :rainbow, version: "2.1.0" override "libffi", version: "3.2.1" override "libiconv", version: "1.14" override "liblzma", version: "5.2.2" diff --git a/spec/data/prefer_metadata_json/metadata.json b/spec/data/prefer_metadata_json/metadata.json new file mode 100644 index 0000000000..eff8836a3b --- /dev/null +++ b/spec/data/prefer_metadata_json/metadata.json @@ -0,0 +1,51 @@ +{ + "name": "prefer_metadata_json", + "description": "", + "long_description": "", + "maintainer": null, + "maintainer_email": null, + "license": "All rights reserved", + "platforms": { + + }, + "dependencies": { + + }, + "recommendations": { + + }, + "suggestions": { + + }, + "conflicting": { + + }, + "providing": { + + }, + "replacing": { + + }, + "attributes": { + + }, + "groupings": { + + }, + "recipes": { + + }, + "version": "1.2.3", + "source_url": "", + "issues_url": "", + "privacy": false, + "chef_versions": [ + + ], + "ohai_versions": [ + + ], + "gems": [ + + ] +} diff --git a/spec/data/prefer_metadata_json/metadata.rb b/spec/data/prefer_metadata_json/metadata.rb new file mode 100644 index 0000000000..a46aa29a5c --- /dev/null +++ b/spec/data/prefer_metadata_json/metadata.rb @@ -0,0 +1,6 @@ +# these deliberately do not match metadata.json +name "test" +version "0.0.1" + +# this raises hard if anything even tries to parse it +raise "TEH SADNESS" diff --git a/spec/data/prefer_metadata_json/recipes/default.rb b/spec/data/prefer_metadata_json/recipes/default.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/spec/data/prefer_metadata_json/recipes/default.rb diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.i686.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.i686.rpm Binary files differnew file mode 100644 index 0000000000..29a4624971 --- /dev/null +++ b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.i686.rpm diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.src.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.src.rpm Binary files differnew file mode 100644 index 0000000000..b6a6ec3176 --- /dev/null +++ b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.src.rpm diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm Binary files differnew file mode 100644 index 0000000000..239b6ef145 --- /dev/null +++ b/spec/functional/assets/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.i686.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.i686.rpm Binary files differnew file mode 100644 index 0000000000..3421c3628f --- /dev/null +++ b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.i686.rpm diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.src.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.src.rpm Binary files differnew file mode 100644 index 0000000000..d420659fd5 --- /dev/null +++ b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.src.rpm diff --git a/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm Binary files differnew file mode 100644 index 0000000000..93c1f5e3e3 --- /dev/null +++ b/spec/functional/assets/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm diff --git a/spec/functional/assets/yumrepo/repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2 b/spec/functional/assets/yumrepo/repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2 Binary files differnew file mode 100644 index 0000000000..d7726b9df6 --- /dev/null +++ b/spec/functional/assets/yumrepo/repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2 diff --git a/spec/functional/assets/yumrepo/repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz b/spec/functional/assets/yumrepo/repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz Binary files differnew file mode 100644 index 0000000000..30d7778ac4 --- /dev/null +++ b/spec/functional/assets/yumrepo/repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz diff --git a/spec/functional/assets/yumrepo/repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2 b/spec/functional/assets/yumrepo/repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2 Binary files differnew file mode 100644 index 0000000000..2df608aa34 --- /dev/null +++ b/spec/functional/assets/yumrepo/repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2 diff --git a/spec/functional/assets/yumrepo/repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz b/spec/functional/assets/yumrepo/repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz Binary files differnew file mode 100644 index 0000000000..d9b7cb879a --- /dev/null +++ b/spec/functional/assets/yumrepo/repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz diff --git a/spec/functional/assets/yumrepo/repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz b/spec/functional/assets/yumrepo/repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz Binary files differnew file mode 100644 index 0000000000..35a973d170 --- /dev/null +++ b/spec/functional/assets/yumrepo/repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz diff --git a/spec/functional/assets/yumrepo/repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2 b/spec/functional/assets/yumrepo/repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2 Binary files differnew file mode 100644 index 0000000000..e682fc0f0b --- /dev/null +++ b/spec/functional/assets/yumrepo/repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2 diff --git a/spec/functional/assets/yumrepo/repodata/repomd.xml b/spec/functional/assets/yumrepo/repodata/repomd.xml new file mode 100644 index 0000000000..92937e151a --- /dev/null +++ b/spec/functional/assets/yumrepo/repodata/repomd.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm"> + <revision>1479418959</revision> +<data type="filelists"> + <checksum type="sha256">8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16</checksum> + <open-checksum type="sha256">9f5be999b4a535c19afc53703851577e1a325227fab651189c5c39708b9a1e38</open-checksum> + <location href="repodata/8b34697595fcc87928e12d24644dda9462c3857bd932861e28bc77ae1f31be16-filelists.xml.gz"/> + <timestamp>1479418959</timestamp> + <size>419</size> + <open-size>1127</open-size> +</data> +<data type="primary"> + <checksum type="sha256">66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243</checksum> + <open-checksum type="sha256">dc25cfbf4520861130e0ba203d27cc40b183fbb7c576aac33d838fb20a68aa32</open-checksum> + <location href="repodata/66391e53f0510b98b3f0b79f40ba1048026d9a1ef20905d9c40ba6f5411f3243-primary.xml.gz"/> + <timestamp>1479418959</timestamp> + <size>859</size> + <open-size>4529</open-size> +</data> +<data type="primary_db"> + <checksum type="sha256">313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0</checksum> + <open-checksum type="sha256">720b637c782cce8604b922e9989ecfff9091e26163d643bd1b676778beb1c933</open-checksum> + <location href="repodata/313329137b55fd333b2dc66394a6661a2befa6cc535d8460d92a4a78a9c581f0-primary.sqlite.bz2"/> + <timestamp>1479418959</timestamp> + <database_version>10</database_version> + <size>2460</size> + <open-size>32768</open-size> +</data> +<data type="other_db"> + <checksum type="sha256">b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc</checksum> + <open-checksum type="sha256">938156bcfc95828cb6857e1b2790dceaef57196843a80464ba5749772fc15e83</open-checksum> + <location href="repodata/b97cca3fe14bcf06c52be4449b6108f7731239ff221111dcce8aada5467f60dc-other.sqlite.bz2"/> + <timestamp>1479418959</timestamp> + <database_version>10</database_version> + <size>967</size> + <open-size>6144</open-size> +</data> +<data type="other"> + <checksum type="sha256">31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553</checksum> + <open-checksum type="sha256">2ea64cdb2f5ba3859af29fe67a85d61d5b4de23f3da1ee71d5af175d8d887ab6</open-checksum> + <location href="repodata/31ac4db5d5ac593728fcc26aef82b7b93c4cc4dbec843786b1845b939b658553-other.xml.gz"/> + <timestamp>1479418959</timestamp> + <size>413</size> + <open-size>1035</open-size> +</data> +<data type="filelists_db"> + <checksum type="sha256">4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773</checksum> + <open-checksum type="sha256">8bc15efa19d02a5112e20c6ed1be17c5851287ddfba17aee2283ddb216dd08d7</open-checksum> + <location href="repodata/4ac40fa3c6728c1401318e2e20a997436624e83dcf7a5f952b851ef422637773-filelists.sqlite.bz2"/> + <timestamp>1479418959</timestamp> + <database_version>10</database_version> + <size>1131</size> + <open-size>7168</open-size> +</data> +</repomd> diff --git a/spec/functional/knife/ssh_spec.rb b/spec/functional/knife/ssh_spec.rb index 065b646ac6..aea7585bb2 100644 --- a/spec/functional/knife/ssh_spec.rb +++ b/spec/functional/knife/ssh_spec.rb @@ -181,7 +181,7 @@ describe Chef::Knife::Ssh do it "uses the ssh_attribute" do @knife.run - expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("ec2.public_hostname") + expect(@knife.get_ssh_attribute({ "knife_config" => "ec2.public_hostname" })).to eq("ec2.public_hostname") end end @@ -193,11 +193,11 @@ describe Chef::Knife::Ssh do it "uses the default" do @knife.run - expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("fqdn") + expect(@knife.get_ssh_attribute({ "fqdn" => "fqdn" })).to eq("fqdn") end end - context "when -a ec2.public_ipv4 is provided" do + context "when -a ec2.public_public_hostname is provided" do before do setup_knife(["-a ec2.public_hostname", "*:*", "uptime"]) Chef::Config[:knife][:ssh_attribute] = nil @@ -276,8 +276,8 @@ describe Chef::Knife::Ssh do Chef::Config[:client_key] = nil Chef::Config[:chef_server_url] = "http://localhost:9000" - @api.get("/search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0", 200) do - %({"total":1, "start":0, "rows":[{"name":"i-xxxxxxxx", "json_class":"Chef::Node", "automatic":{"fqdn":"the.fqdn", "ec2":{"public_hostname":"the_public_hostname"}},"recipes":[]}]}) + @api.post("/search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0", 200) do + %({"total":1, "start":0, "rows":[{"data": {"fqdn":"the.fqdn", "config": "the_public_hostname", "knife_config": "the_public_hostname" }}]}) end end diff --git a/spec/functional/resource/dnf_package_spec.rb b/spec/functional/resource/dnf_package_spec.rb new file mode 100644 index 0000000000..4c9ee6ca97 --- /dev/null +++ b/spec/functional/resource/dnf_package_spec.rb @@ -0,0 +1,686 @@ +# +# Copyright:: Copyright 2016, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" +require "functional/resource/base" +require "chef/mixin/shell_out" + +# run this test only for following platforms. +exclude_test = !(%w{rhel fedora}.include?(ohai[:platform_family]) && File.exist?("/usr/bin/dnf")) +describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do + include Chef::Mixin::ShellOut + + def flush_cache + # needed on at least fc23/fc24 sometimes to deal with the dnf cache getting out of sync with the rpm db + FileUtils.rm_f "/var/cache/dnf/@System.solv" + Chef::Resource::DnfPackage.new("shouldnt-matter", run_context).run_action(:flush_cache) + end + + def preinstall(*rpms) + rpms.each do |rpm| + shell_out!("rpm -ivh #{CHEF_SPEC_ASSETS}/yumrepo/#{rpm}") + end + flush_cache + end + + before(:each) do + File.open("/etc/yum.repos.d/chef-dnf-localtesting.repo", "w+") do |f| + f.write <<-EOF +[chef-dnf-localtesting] +name=Chef DNF spec testing repo +baseurl=file://#{CHEF_SPEC_ASSETS}/yumrepo +enable=1 +gpgcheck=0 + EOF + end + shell_out!("rpm -qa | grep chef_rpm | xargs -r rpm -e") + end + + after(:all) do + shell_out!("rpm -qa | grep chef_rpm | xargs -r rpm -e") + FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo" + end + + let(:package_name) { "chef_rpm" } + let(:dnf_package) { Chef::Resource::DnfPackage.new(package_name, run_context) } + + describe ":install" do + context "vanilla use case" do + let(:package_name) { "chef_rpm" } + + it "installs if the package is not installed" do + flush_cache + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "does not install if the package is installed" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "does not install twice" do + flush_cache + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "does not install if the prior version package is installed" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "does not install if the i686 package is installed" do + skip "FIXME: do nothing, or install the x86_64 version?" + preinstall("chef_rpm-1.10-1.fc24.i686.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686") + end + + it "does not install if the prior version i686 package is installed" do + skip "FIXME: do nothing, or install the x86_64 version?" + preinstall("chef_rpm-1.2-1.fc24.i686.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.i686") + end + end + + context "with versions or globs in the name" do + it "works with a version" do + flush_cache + dnf_package.package_name("chef_rpm-1.10") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "works with an older version" do + flush_cache + dnf_package.package_name("chef_rpm-1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "works with an evr" do + flush_cache + dnf_package.package_name("chef_rpm-0:1.2-1.fc24") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "works with a version glob" do + flush_cache + dnf_package.package_name("chef_rpm-1*") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "works with a name glob + version glob" do + flush_cache + dnf_package.package_name("chef_rp*-1*") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + end + + # version only matches the actual dnf version, does not work with epoch or release or combined evr + context "with version property" do + it "matches the full version" do + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.version("1.10") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "matches with a glob" do + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.version("1*") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "matches the vr" do + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.version("1.10-1.fc24") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "matches the evr" do + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.version("0:1.10-1.fc24") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "matches with a vr glob" do + pending "doesn't work on command line either" + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.version("1.10-1*") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "matches with an evr glob" do + pending "doesn't work on command line either" + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.version("0:1.10-1*") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + end + + context "downgrades" do + it "just work with DNF" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.version("1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "throws a deprecation warning with allow_downgrade" do + Chef::Config[:treat_deprecation_warnings_as_errors] = false + expect(Chef).to receive(:deprecated).with(:dnf_package_allow_downgrade, /^the allow_downgrade property on the dnf_package provider is not used/) + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.version("1.2") + dnf_package.run_action(:install) + dnf_package.allow_downgrade true + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + end + + context "with arches" do + it "installs with 64-bit arch in the name" do + flush_cache + dnf_package.package_name("chef_rpm.x86_64") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "installs with 32-bit arch in the name" do + flush_cache + dnf_package.package_name("chef_rpm.i686") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686") + end + + it "installs with 64-bit arch in the property" do + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.arch("x86_64") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "installs with 32-bit arch in the property" do + flush_cache + dnf_package.package_name("chef_rpm") + dnf_package.arch("i686") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686") + end + end + + context "with constraints" do + it "with nothing installed, it installs the latest version" do + flush_cache + dnf_package.package_name("chef_rpm >= 1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "when it is met, it does nothing" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.package_name("chef_rpm >= 1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "when it is met, it does nothing" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name("chef_rpm >= 1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "with nothing intalled, it installs the latest version" do + flush_cache + dnf_package.package_name("chef_rpm > 1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "when it is not met by an installed rpm, it upgrades" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.package_name("chef_rpm > 1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "when it is met by an installed rpm, it does nothing" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name("chef_rpm > 1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "when there is no solution to the contraint" do + flush_cache + dnf_package.package_name("chef_rpm > 2.0") + expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/) + end + + it "when there is no solution to the contraint but an rpm is preinstalled" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name("chef_rpm > 2.0") + expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/) + end + end + + context "with source arguments" do + it "raises an exception when the package does not exist" do + flush_cache + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm") + expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/) + end + + it "does not raise a hard exception in why-run mode when the package does not exist" do + Chef::Config[:why_run] = true + flush_cache + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm") + dnf_package.run_action(:install) + expect { dnf_package.run_action(:install) }.not_to raise_error + end + + it "installs the package when using the source argument" do + flush_cache + dnf_package.name "something" + dnf_package.package_name "somethingelse" + dnf_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "installs the package when the name is a path to a file" do + flush_cache + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "does not downgrade the package with :install" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "does not upgrade the package with :install" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "is idempotent when the package is already installed" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + end + + context "with no available version" do + it "works when a package is installed" do + FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo" + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "works with a local source" do + FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo" + flush_cache + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + end + + context "multipackage with arches" do + it "installs two rpms" do + flush_cache + dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] ) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/) + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/) + end + + it "does nothing if both are installed" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm", "chef_rpm-1.10-1.fc24.i686.rpm") + flush_cache + dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] ) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + end + + it "installs the second rpm if the first is installed" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] ) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/) + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/) + end + + it "installs the first rpm if the second is installed" do + preinstall("chef_rpm-1.10-1.fc24.i686.rpm") + dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] ) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/) + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/) + end + + # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name + it "installs two rpms with multi-arch" do + flush_cache + dnf_package.package_name(%w{chef_rpm chef_rpm} ) + dnf_package.arch(%w{x86_64 i686}) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/) + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/) + end + + # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name + it "installs the second rpm if the first is installed (muti-arch)" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name(%w{chef_rpm chef_rpm} ) + dnf_package.arch(%w{x86_64 i686}) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/) + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/) + end + + # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name + it "installs the first rpm if the second is installed (muti-arch)" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name(%w{chef_rpm chef_rpm} ) + dnf_package.arch(%w{x86_64 i686}) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.x86_64/) + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.fc24.i686/) + end + + # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name + it "does nothing if both are installed (muti-arch)" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm", "chef_rpm-1.10-1.fc24.i686.rpm") + dnf_package.package_name(%w{chef_rpm chef_rpm} ) + dnf_package.arch(%w{x86_64 i686}) + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be false + end + end + end + + describe ":upgrade" do + context "downgrades" do + it "just work with DNF" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.version("1.2") + dnf_package.run_action(:install) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "throws a deprecation warning with allow_downgrade" do + Chef::Config[:treat_deprecation_warnings_as_errors] = false + expect(Chef).to receive(:deprecated).with(:dnf_package_allow_downgrade, /^the allow_downgrade property on the dnf_package provider is not used/) + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.version("1.2") + dnf_package.run_action(:install) + dnf_package.allow_downgrade true + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + end + + context "with source arguments" do + it "installs the package when using the source argument" do + flush_cache + dnf_package.name "something" + dnf_package.package_name "somethingelse" + dnf_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:upgrade) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "installs the package when the name is a path to a file" do + flush_cache + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:upgrade) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "downgrades the package" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:upgrade) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "upgrades the package" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.run_action(:upgrade) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + + it "is idempotent when the package is already installed" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:upgrade) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + end + + context "with no available version" do + it "works when a package is installed" do + FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo" + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:upgrade) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + + it "works with a local source" do + FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo" + flush_cache + dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:upgrade) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.x86_64") + end + end + end + + describe ":remove" do + context "vanilla use case" do + let(:package_name) { "chef_rpm" } + it "does nothing if the package is not installed" do + flush_cache + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "removes the package if the package is installed" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "does not remove the package twice" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "removes the package if the prior version package is installed" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "removes the package if the i686 package is installed" do + skip "FIXME: should this be fixed or is the current behavior correct?" + preinstall("chef_rpm-1.10-1.fc24.i686.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "removes the package if the prior version i686 package is installed" do + skip "FIXME: should this be fixed or is the current behavior correct?" + preinstall("chef_rpm-1.2-1.fc24.i686.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + end + + context "with 64-bit arch" do + let(:package_name) { "chef_rpm.x86_64" } + it "does nothing if the package is not installed" do + flush_cache + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "removes the package if the package is installed" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "removes the package if the prior version package is installed" do + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + + it "does nothing if the i686 package is installed" do + preinstall("chef_rpm-1.10-1.fc24.i686.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.i686") + end + + it "does nothing if the prior version i686 package is installed" do + preinstall("chef_rpm-1.2-1.fc24.i686.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be false + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.fc24.i686") + end + end + + context "with 32-bit arch" do + let(:package_name) { "chef_rpm.i686" } + it "removes only the 32-bit arch if both are installed" do + preinstall("chef_rpm-1.10-1.fc24.x86_64.rpm", "chef_rpm-1.10-1.fc24.i686.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.fc24.x86_64") + end + end + + context "with no available version" do + it "works when a package is installed" do + FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo" + preinstall("chef_rpm-1.2-1.fc24.x86_64.rpm") + dnf_package.run_action(:remove) + expect(dnf_package.updated_by_last_action?).to be true + expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed") + end + end + end +end diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb index 268ce5c9d2..497cb0b043 100644 --- a/spec/functional/resource/user/useradd_spec.rb +++ b/spec/functional/resource/user/useradd_spec.rb @@ -645,6 +645,15 @@ describe Chef::Provider::User::Useradd, metadata do expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed) expect(@error.message).to include("Cannot unlock the password") end + elsif %w{rhel}.include?(OHAI_SYSTEM["platform_family"]) && + OHAI_SYSTEM["platform_version"].to_f == 6.8 + # usermod -U returns following message for rhel68 on s390x platforms + # usermod: unlocking the user's password would result in a passwordless account. + #You should set a password with usermod -p to unlock this user's password. + it "errors out trying to unlock the user" do + expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed) + expect(@error.message).to include("You should set a password") + end else # borked on all other platforms: diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb index da3a2b98e4..7a8059066a 100644 --- a/spec/integration/client/client_spec.rb +++ b/spec/integration/client/client_spec.rb @@ -46,6 +46,7 @@ describe "chef-client" do # we're running `chef-client` from the source tree and not the external one. # cf. CHEF-4914 let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" } + let(:chef_solo) { "ruby '#{chef_dir}/chef-solo' --minimal-ohai" } let(:critical_env_vars) { %w{_ORIGINAL_GEM_PATH GEM_PATH GEM_HOME GEM_ROOT BUNDLE_BIN_PATH BUNDLE_GEMFILE RUBYLIB RUBYOPT RUBY_ENGINE RUBY_ROOT RUBY_VERSION PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") } @@ -499,4 +500,36 @@ EOM expect(result.exitstatus).not_to eq(0) end end + + when_the_repository "has a cookbook with broken metadata.rb, but has metadata.json" do + before do + file "cookbooks/x/recipes/default.rb", "" + file "cookbooks/x/metadata.rb", <<EOM +name 'x' +version '0.0.1' +raise "TEH SADNESS" +EOM + file "cookbooks/x/metadata.json", <<EOM +{ + "name": "x", + "version": "0.0.1" +} +EOM + + file "config/client.rb", <<EOM +local_mode true +cookbook_path "#{path_to('cookbooks')}" +EOM + end + + it "the chef client run should succeed" do + command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir) + command.error! + end + + it "a chef-solo run should succeed" do + command = shell_out("#{chef_solo} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir) + command.error! + end + end end diff --git a/spec/support/shared/unit/provider/file.rb b/spec/support/shared/unit/provider/file.rb index 394fdaa02f..b58159fcc9 100644 --- a/spec/support/shared/unit/provider/file.rb +++ b/spec/support/shared/unit/provider/file.rb @@ -683,6 +683,16 @@ shared_examples_for Chef::Provider::File do end end + context "in why run mode" do + before { Chef::Config[:why_run] = true } + after { Chef::Config[:why_run] = false } + + it "does not modify new_resource" do + setup_missing_file + expect(provider).not_to receive(:load_resource_attributes_from_file).with(provider.new_resource) + provider.run_action(:create) + end + end end context "action delete" do diff --git a/spec/unit/cookbook/cookbook_version_loader_spec.rb b/spec/unit/cookbook/cookbook_version_loader_spec.rb index 87d0f1e032..786e17f35b 100644 --- a/spec/unit/cookbook/cookbook_version_loader_spec.rb +++ b/spec/unit/cookbook/cookbook_version_loader_spec.rb @@ -104,6 +104,15 @@ describe Chef::Cookbook::CookbookVersionLoader do end + context "when a cookbook's metadata.rb does not parse but the compiled metadata.json is present" do + let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "prefer_metadata_json") } + + it "reads the cookbook" do + expect(loaded_cookbook.metadata.name.to_s).to eq("prefer_metadata_json") + expect(loaded_cookbook.metadata.version.to_s).to eq("1.2.3") + end + end + context "when the given path is not actually a cookbook" do let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks/NOTHING_HERE_FOLKS") } diff --git a/spec/unit/knife/ssh_spec.rb b/spec/unit/knife/ssh_spec.rb index 44a133d858..6141a8a6df 100644 --- a/spec/unit/knife/ssh_spec.rb +++ b/spec/unit/knife/ssh_spec.rb @@ -21,54 +21,53 @@ require "net/ssh" require "net/ssh/multi" describe Chef::Knife::Ssh do - before(:each) do - Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" - end + let(:query_result) { double("chef search results") } before do + Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" @knife = Chef::Knife::Ssh.new @knife.merge_configs - @node_foo = Chef::Node.new - @node_foo.automatic_attrs[:fqdn] = "foo.example.org" - @node_foo.automatic_attrs[:ipaddress] = "10.0.0.1" + @node_foo = {} + @node_foo["fqdn"] = "foo.example.org" + @node_foo["ipaddress"] = "10.0.0.1" + @node_foo["cloud"] = {} + + @node_bar = {} + @node_bar["fqdn"] = "bar.example.org" + @node_bar["ipaddress"] = "10.0.0.2" + @node_bar["cloud"] = {} - @node_bar = Chef::Node.new - @node_bar.automatic_attrs[:fqdn] = "bar.example.org" - @node_bar.automatic_attrs[:ipaddress] = "10.0.0.2" end describe "#configure_session" do context "manual is set to false (default)" do before do @knife.config[:manual] = false - @query = Chef::Search::Query.new - end - - def configure_query(node_array) - allow(@query).to receive(:search).and_return([node_array]) - allow(Chef::Search::Query).to receive(:new).and_return(@query) + allow(query_result).to receive(:search).with(any_args).and_yield(@node_foo).and_yield(@node_bar) + allow(Chef::Search::Query).to receive(:new).and_return(query_result) end def self.should_return_specified_attributes it "returns an array of the attributes specified on the command line OR config file, if only one is set" do + @node_bar["config"] = "10.0.0.2" + @node_foo["config"] = "10.0.0.1" @knife.config[:attribute] = "ipaddress" Chef::Config[:knife][:ssh_attribute] = "ipaddress" # this value will be in the config file - configure_query([@node_foo, @node_bar]) expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]]) @knife.configure_session end it "returns an array of the attributes specified on the command line even when a config value is set" do + @node_bar["config"] = "10.0.0.2" + @node_foo["config"] = "10.0.0.1" Chef::Config[:knife][:ssh_attribute] = "config_file" # this value will be in the config file @knife.config[:attribute] = "ipaddress" # this is the value of the command line via #configure_attribute - configure_query([@node_foo, @node_bar]) expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]]) @knife.configure_session end end it "searchs for and returns an array of fqdns" do - configure_query([@node_foo, @node_bar]) expect(@knife).to receive(:session_from_list).with([ ["foo.example.org", nil], ["bar.example.org", nil], @@ -80,11 +79,10 @@ describe Chef::Knife::Ssh do context "when cloud hostnames are available" do before do - @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com" - @node_bar.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-2.compute-1.amazonaws.com" + @node_foo["cloud"]["public_hostname"] = "ec2-10-0-0-1.compute-1.amazonaws.com" + @node_bar["cloud"]["public_hostname"] = "ec2-10-0-0-2.compute-1.amazonaws.com" end it "returns an array of cloud public hostnames" do - configure_query([@node_foo, @node_bar]) expect(@knife).to receive(:session_from_list).with([ ["ec2-10-0-0-1.compute-1.amazonaws.com", nil], ["ec2-10-0-0-2.compute-1.amazonaws.com", nil], @@ -97,12 +95,11 @@ describe Chef::Knife::Ssh do context "when cloud hostnames are available but empty" do before do - @node_foo.automatic_attrs[:cloud][:public_hostname] = "" - @node_bar.automatic_attrs[:cloud][:public_hostname] = "" + @node_foo["cloud"]["public_hostname"] = "" + @node_bar["cloud"]["public_hostname"] = "" end it "returns an array of fqdns" do - configure_query([@node_foo, @node_bar]) expect(@knife).to receive(:session_from_list).with([ ["foo.example.org", nil], ["bar.example.org", nil], @@ -114,7 +111,7 @@ describe Chef::Knife::Ssh do end it "should raise an error if no host are found" do - configure_query([ ]) + allow(query_result).to receive(:search).with(any_args) expect(@knife.ui).to receive(:fatal) expect(@knife).to receive(:exit).with(10) @knife.configure_session @@ -122,10 +119,8 @@ describe Chef::Knife::Ssh do context "when there are some hosts found but they do not have an attribute to connect with" do before do - allow(@query).to receive(:search).and_return([[@node_foo, @node_bar]]) - @node_foo.automatic_attrs[:fqdn] = nil - @node_bar.automatic_attrs[:fqdn] = nil - allow(Chef::Search::Query).to receive(:new).and_return(@query) + @node_foo["fqdn"] = nil + @node_bar["fqdn"] = nil end it "should raise a specific error (CHEF-3402)" do @@ -158,31 +153,34 @@ describe Chef::Knife::Ssh do before do Chef::Config[:knife][:ssh_attribute] = nil @knife.config[:attribute] = nil - @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com" - @node_bar.automatic_attrs[:cloud][:public_hostname] = "" + @node_foo["cloud"]["public_hostname"] = "ec2-10-0-0-1.compute-1.amazonaws.com" + @node_bar["cloud"]["public_hostname"] = "" end it "should return fqdn by default" do - expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("fqdn") + expect(@knife.get_ssh_attribute({ "fqdn" => "fqdn" })).to eq("fqdn") end it "should return cloud.public_hostname attribute if available" do - expect(@knife.get_ssh_attribute(@node_foo)).to eq("cloud.public_hostname") + expect(@knife.get_ssh_attribute(@node_foo)).to eq("ec2-10-0-0-1.compute-1.amazonaws.com") end it "should favor to attribute_from_cli over config file and cloud" do @knife.config[:attribute] = "command_line" Chef::Config[:knife][:ssh_attribute] = "config_file" + @node_foo["config"] = "command_line" + @node_foo["knife_config"] = "config_file" expect( @knife.get_ssh_attribute(@node_foo)).to eq("command_line") end it "should favor config file over cloud and default" do Chef::Config[:knife][:ssh_attribute] = "config_file" + @node_foo["knife_config"] = "config_file" expect( @knife.get_ssh_attribute(@node_foo)).to eq("config_file") end it "should return fqdn if cloud.hostname is empty" do - expect( @knife.get_ssh_attribute(@node_bar)).to eq("fqdn") + expect( @knife.get_ssh_attribute(@node_bar)).to eq("bar.example.org") end end @@ -190,7 +188,7 @@ describe Chef::Knife::Ssh do before :each do @knife.instance_variable_set(:@longest, 0) ssh_config = { :timeout => 50, :user => "locutus", :port => 23 } - allow(Net::SSH).to receive(:configuration_for).with("the.b.org").and_return(ssh_config) + allow(Net::SSH).to receive(:configuration_for).with("the.b.org", true).and_return(ssh_config) end it "uses the port from an ssh config file" do @@ -294,7 +292,7 @@ describe Chef::Knife::Ssh do describe "#run" do before do @query = Chef::Search::Query.new - expect(@query).to receive(:search).and_return([[@node_foo]]) + expect(@query).to receive(:search).and_yield(@node_foo) allow(Chef::Search::Query).to receive(:new).and_return(@query) allow(@knife).to receive(:ssh_command).and_return(exit_code) @knife.name_args = ["*:*", "false"] diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index 59b4b8a1c7..ac227c5479 100644 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -337,14 +337,35 @@ describe Chef::Node do Chef::Config[:treat_deprecation_warnings_as_errors] = false expect(Chef).to receive(:deprecated).with(:attributes, /set is deprecated/) node.set[:snoopy][:is_a_puppy] = true - expect(node[:snoopy][:is_a_puppy]).to eq(true) + expect(node.normal[:snoopy][:is_a_puppy]).to eq(true) end it "set_unless is a deprecated alias for normal_unless" do Chef::Config[:treat_deprecation_warnings_as_errors] = false expect(Chef).to receive(:deprecated).with(:attributes, /set_unless is deprecated/) node.set_unless[:snoopy][:is_a_puppy] = false - expect(node[:snoopy][:is_a_puppy]).to eq(false) + expect(node.normal[:snoopy][:is_a_puppy]).to eq(false) + end + + it "normal_unless sets a value even if default or override attrs are set" do + node.default[:decontamination] = true + node.override[:decontamination] = false + node.normal_unless[:decontamination] = "foo" + expect(node.normal[:decontamination]).to eql("foo") + end + + it "default_unless sets a value even if normal or override attrs are set" do + node.normal[:decontamination] = true + node.override[:decontamination] = false + node.default_unless[:decontamination] = "foo" + expect(node.default[:decontamination]).to eql("foo") + end + + it "override_unless sets a value even if default or normal attrs are set" do + node.default[:decontamination] = true + node.normal[:decontamination] = false + node.override_unless[:decontamination] = "foo" + expect(node.override[:decontamination]).to eql("foo") end end diff --git a/spec/unit/provider/directory_spec.rb b/spec/unit/provider/directory_spec.rb index aebbaa6e81..4672db7d8d 100644 --- a/spec/unit/provider/directory_spec.rb +++ b/spec/unit/provider/directory_spec.rb @@ -148,6 +148,16 @@ describe Chef::Provider::Directory do directory.run_action(:create) expect(new_resource).not_to be_updated end + + context "in why run mode" do + before { Chef::Config[:why_run] = true } + after { Chef::Config[:why_run] = false } + + it "does not modify new_resource" do + expect(directory).not_to receive(:load_resource_attributes_from_file).with(new_resource) + directory.run_action(:create) + end + end end describe "when the directory does not exist" do diff --git a/spec/unit/provider/dsc_resource_spec.rb b/spec/unit/provider/dsc_resource_spec.rb index 34eb9727f8..96356e5d73 100644 --- a/spec/unit/provider/dsc_resource_spec.rb +++ b/spec/unit/provider/dsc_resource_spec.rb @@ -165,4 +165,179 @@ describe Chef::Provider::DscResource do end end end + + describe "define_resource_requirements" do + let (:node) do + set_node_object + end + + context "module usage is valid" do + before do + allow(provider).to receive(:module_usage_valid?).and_return(true) + allow(provider).to receive(:action_run) + end + + [:run].each do |action| + context "action #{action}" do + it "does not raise the exception" do + expect { provider.run_action(action) }.not_to raise_error + end + end + end + end + + context "module usage is invalid" do + before do + allow(provider).to receive(:module_usage_valid?).and_return(false) + allow(provider).to receive(:action_run) + end + + [:run].each do |action| + context "action #{action}" do + it "raises the exception" do + expect { provider.run_action(action) }.to raise_error( + Chef::Exceptions::DSCModuleNameMissing + ) + end + end + end + end + end + + describe "module_usage_valid?" do + let (:node) do + set_node_object + end + + context "module_name and module_version both are not provided" do + before do + provider.instance_variable_set(:@module_name, nil) + provider.instance_variable_set(:@module_version, nil) + end + + it "returns true" do + response = provider.send(:module_usage_valid?) + expect(response).to be == true + end + end + + context "module_name and module_version both are provided" do + before do + provider.instance_variable_set(:@module_name, "my_module") + provider.instance_variable_set(:@module_version, "1.3") + end + + it "returns true" do + response = provider.send(:module_usage_valid?) + expect(response).to be == true + end + end + + context "module_name is given but module_version is not given" do + before do + provider.instance_variable_set(:@module_name, "my_module") + provider.instance_variable_set(:@module_version, nil) + end + + it "returns true" do + response = provider.send(:module_usage_valid?) + expect(response).to be == true + end + end + + context "module_name is not given but module_version is given" do + before do + provider.instance_variable_set(:@module_name, nil) + provider.instance_variable_set(:@module_version, "1.4.0.1") + end + + it "returns false" do + response = provider.send(:module_usage_valid?) + expect(response).to be == false + end + end + end + + describe "module_info_object" do + let (:node) do + set_node_object + end + + context "module_version is not given" do + before do + provider.instance_variable_set(:@module_version, nil) + allow(provider).to receive(:module_name).and_return("my_module") + end + + it "returns only name of the module" do + response = provider.send(:module_info_object) + expect(response).to be == "my_module" + end + end + + context "module_version is given" do + before do + provider.instance_variable_set(:@module_version, "1.3.1") + allow(provider).to receive(:module_name).and_return("my_module") + end + + it "returns the module info object" do + response = provider.send(:module_info_object) + expect(response).to be == "@{ModuleName='my_module';ModuleVersion='1.3.1'}" + end + end + end + + describe "invoke_resource" do + let (:node) do + set_node_object + end + + let(:cmdlet) { double(:run! => nil) } + + before(:each) do + allow(provider).to receive(:translate_type).and_return("my_properties") + provider.instance_variable_set(:@new_resource, double( + :properties => "my_properties", :resource => "my_resource", :timeout => 123 + )) + end + + context "when module_version is not given" do + before do + allow(provider).to receive(:module_info_object).and_return("my_module") + end + + it "invokes Invoke-DscResource command with module name" do + expect(Chef::Util::Powershell::Cmdlet).to receive(:new).with( + node, + "Invoke-DscResource -Method my_method -Name my_resource -Property my_properties -Module my_module -Verbose", + "my_output_format" + ).and_return(cmdlet) + provider.send(:invoke_resource, "my_method", "my_output_format") + end + end + + context "when module_version is given" do + before do + allow(provider).to receive(:module_info_object).and_return( + "@{ModuleName='my_module';ModuleVersion='my_module_version'}" + ) + end + + it "invokes Invoke-DscResource command with module info object" do + expect(Chef::Util::Powershell::Cmdlet).to receive(:new).with( + node, + "Invoke-DscResource -Method my_method -Name my_resource -Property my_properties -Module @{ModuleName='my_module';ModuleVersion='my_module_version'} -Verbose", + "my_output_format" + ).and_return(cmdlet) + provider.send(:invoke_resource, "my_method", "my_output_format") + end + end + end +end + +def set_node_object + node = Chef::Node.new + node.automatic[:languages][:powershell][:version] = "5.0.10586.0" + node end diff --git a/spec/unit/provider/launchd_spec.rb b/spec/unit/provider/launchd_spec.rb index 3e45433c62..693801f99b 100644 --- a/spec/unit/provider/launchd_spec.rb +++ b/spec/unit/provider/launchd_spec.rb @@ -185,8 +185,8 @@ XML end describe "hash is passed" do - it "should produce the test_plist from the hash" do - new_resource.hash test_hash + it "should produce the test_plist content from the plist_hash property" do + new_resource.plist_hash test_hash expect(provider.content?).to be_truthy expect(provider.content).to eql(test_plist) end diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb index 2b574bb7df..dba56b186d 100644 --- a/spec/unit/provider/package/aix_spec.rb +++ b/spec/unit/provider/package/aix_spec.rb @@ -28,7 +28,7 @@ describe Chef::Provider::Package::Aix do @new_resource.source("/tmp/samba.base") @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) - allow(::File).to receive(:exists?).and_return(true) + allow(::File).to receive(:exists?).with(@new_resource.source).and_return(true) end describe "assessing the current package status" do @@ -57,7 +57,7 @@ describe Chef::Provider::Package::Aix do it "should raise an exception if a source is supplied but not found" do allow(@provider).to receive(:shell_out).and_return(@empty_status) - allow(::File).to receive(:exists?).and_return(false) + allow(::File).to receive(:exists?).with(@new_resource.source).and_return(false) @provider.load_current_resource @provider.define_resource_requirements expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Package) @@ -154,7 +154,7 @@ describe Chef::Provider::Package::Aix do @provider.install_package("samba.base", "3.3.12.0") end - it "should run when the package is a path to install" do + it "should run installp -aYF -d when the package is a path to install" do @new_resource = Chef::Resource::Package.new("/tmp/samba.base") @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) expect(@new_resource.source).to eq("/tmp/samba.base") diff --git a/spec/unit/provider/package/cab_spec.rb b/spec/unit/provider/package/cab_spec.rb index 5e16795aa8..5c86f781f3 100644 --- a/spec/unit/provider/package/cab_spec.rb +++ b/spec/unit/provider/package/cab_spec.rb @@ -49,7 +49,7 @@ The operation completed successfully end before do - new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.cab" + new_resource.source = File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab") installed_package_list_obj = double(stdout: installed_package_list_stdout) allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj) package_version_obj = double(stdout: package_version_stdout) @@ -126,6 +126,63 @@ The operation completed successfully. end end + describe "#source_resource" do + before do + new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.cab" + new_resource.cookbook_name = "cab_package" + end + + it "sets the desired parameters of downloades cab file" do + allow(provider).to receive(:default_download_cache_path).and_return("C:\\chef\\cache\\package") + source_resource = provider.source_resource + expect(source_resource.path).to be == "C:\\chef\\cache\\package" + expect(source_resource.name).to be == "windows_test_pkg" + expect(source_resource.source).to be == [new_resource.source] + expect(source_resource.cookbook_name).to be == "cab_package" + end + end + + describe "#default_download_cache_path" do + before do + new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.cab" + end + + it "returns a clean cache path where the cab file is downloaded" do + allow(Chef::FileCache).to receive(:create_cache_path).and_return(ENV["TEMP"]) + path = provider.default_download_cache_path + if windows? + expect(path).to be == File.join("#{ENV['TEMP']}", "\\", "Test6.1-KB2664825-v3-x64.cab") + else + expect(path).to be == File.join("#{ENV['TEMP']}", "Test6.1-KB2664825-v3-x64.cab") + end + end + end + + describe "#cab_file_source" do + context "when local file path is set" do + it "returns local cab file source path" do + new_resource.source = File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab") + path = provider.cab_file_source + if windows? + expect(path).to be == File.join("#{ENV['TEMP'].downcase}", "\\", "test6.1-kb2664825-v3-x64.cab") + else + expect(path).to be == File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab") + end + end + end + context "when url is set" do + it "calls download_source_file method" do + new_resource.source = "https://www.something.com/test6.1-kb2664825-v3-x64.cab" + if windows? + expect(provider).to receive(:download_source_file).and_return(File.join("#{ENV['TEMP'].downcase}", "\\", "test6.1-kb2664825-v3-x64.cab")) + else + expect(provider).to receive(:download_source_file).and_return(File.join("#{ENV['TEMP']}", "test6.1-kb2664825-v3-x64.cab")) + end + provider.cab_file_source + end + end + end + describe "#initialize" do it "returns the correct class" do expect(provider).to be_kind_of(Chef::Provider::Package::Cab) @@ -192,12 +249,9 @@ The operation completed successfully. context "Invalid package source" do def package_version_stdout package_version_stdout = <<-EOF - Deployment Image Servicing and Management tool Version: 6.1.7600.16385 - Image Version: 6.1.7600.16385 - An error occurred trying to open - c:\\temp\\test6.1-KB2664825-v3-x64.cab Error: 0x80070003 Error: 3 The system cannot find the path specified. @@ -206,7 +260,7 @@ The DISM log file can be found at C:\\Windows\\Logs\\DISM\\dism.log. end before do - new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.cab" + new_resource.source = "#{ENV['TEMP']}/test6.1-kb2664825-v3-x64.cab" installed_package_list_obj = double(stdout: installed_package_list_stdout) allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj) end diff --git a/spec/unit/provider/package/chocolatey_spec.rb b/spec/unit/provider/package/chocolatey_spec.rb index 0429a4b202..68b121960c 100644 --- a/spec/unit/provider/package/chocolatey_spec.rb +++ b/spec/unit/provider/package/chocolatey_spec.rb @@ -46,7 +46,7 @@ ConEmu|15.10.25.0 allow(provider).to receive(:choco_install_path).and_return(choco_install_path) allow(provider).to receive(:choco_exe).and_return(choco_exe) local_list_obj = double(:stdout => local_list_stdout) - allow(provider).to receive(:shell_out!).with("#{choco_exe} list -l -r", { :timeout => timeout }).and_return(local_list_obj) + allow(provider).to receive(:shell_out!).with("#{choco_exe} list -l -r", { :returns => [0], :timeout => timeout }).and_return(local_list_obj) end def allow_remote_list(package_names, args = nil) @@ -59,7 +59,7 @@ Git|2.6.2 munin-node|1.6.1.20130823 EOF remote_list_obj = double(stdout: remote_list_stdout) - allow(provider).to receive(:shell_out!).with("#{choco_exe} list -r #{package_names.join ' '}#{args}", { timeout: timeout }).and_return(remote_list_obj) + allow(provider).to receive(:shell_out!).with("#{choco_exe} list -r #{package_names.join ' '}#{args}", { :returns => [0], timeout: timeout }).and_return(remote_list_obj) end describe "#initialize" do @@ -180,7 +180,7 @@ munin-node|1.6.1.20130823 it "should install a single package" do allow_remote_list(["git"]) provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -191,7 +191,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["git"]) new_resource.timeout(timeout) provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -220,7 +220,7 @@ munin-node|1.6.1.20130823 new_resource.package_name("ConEmu") new_resource.version("15.10.25.1") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -233,7 +233,7 @@ munin-node|1.6.1.20130823 new_resource.package_name(%w{chocolatey ConEmu}) new_resource.version([nil, "15.10.25.1"]) provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -243,7 +243,7 @@ munin-node|1.6.1.20130823 new_resource.package_name("conemu") new_resource.version("15.10.25.1") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -253,8 +253,8 @@ munin-node|1.6.1.20130823 new_resource.package_name(%w{ConEmu git}) new_resource.version(["15.10.25.1", nil]) provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double) - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y --version 15.10.25.1 conemu", { :returns => [0], :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -263,7 +263,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["git", "munin-node"]) new_resource.package_name(["git", "munin-node"]) provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git munin-node", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git munin-node", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -273,7 +273,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["git"], " -source localpackages") new_resource.source("localpackages") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -source localpackages git", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -source localpackages git", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -283,7 +283,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["git"]) new_resource.options("-force") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -force git", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -force git", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:install) expect(new_resource).to be_updated_by_last_action end @@ -317,7 +317,7 @@ munin-node|1.6.1.20130823 it "should install a package that is not installed" do allow_remote_list(["git"]) provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y git", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y git", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:upgrade) expect(new_resource).to be_updated_by_last_action end @@ -326,7 +326,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["ConEmu"]) new_resource.package_name("ConEmu") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:upgrade) expect(new_resource).to be_updated_by_last_action end @@ -335,7 +335,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["conemu"]) new_resource.package_name("conemu") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:upgrade) expect(new_resource).to be_updated_by_last_action end @@ -344,7 +344,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["chocolatey"]) new_resource.package_name("chocolatey") provider.load_current_resource - expect(provider).not_to receive(:shell_out!).with("#{choco_exe} upgrade -y chocolatey", { :timeout => timeout }) + expect(provider).not_to receive(:shell_out!).with("#{choco_exe} upgrade -y chocolatey", { :returns => [0], :timeout => timeout }) provider.run_action(:upgrade) expect(new_resource).not_to be_updated_by_last_action end @@ -353,7 +353,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["git"]) new_resource.version("2.6.2") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y --version 2.6.2 git", { :timeout => timeout }) + expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y --version 2.6.2 git", { :returns => [0], :timeout => timeout }) provider.run_action(:upgrade) expect(new_resource).to be_updated_by_last_action end @@ -361,7 +361,7 @@ munin-node|1.6.1.20130823 it "upgrading multiple packages uses a single command" do allow_remote_list(%w{conemu git}) new_resource.package_name(%w{conemu git}) - expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu git", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu git", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:upgrade) expect(new_resource).to be_updated_by_last_action end @@ -413,7 +413,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["ConEmu"]) new_resource.package_name("ConEmu") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y ConEmu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y ConEmu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:remove) expect(new_resource).to be_updated_by_last_action end @@ -422,7 +422,7 @@ munin-node|1.6.1.20130823 allow_remote_list(["conemu"]) new_resource.package_name("conemu") provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:remove) expect(new_resource).to be_updated_by_last_action end @@ -432,7 +432,7 @@ munin-node|1.6.1.20130823 allow_remote_list(%w{git conemu}) new_resource.package_name(%w{git conemu}) provider.load_current_resource - expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :timeout => timeout }).and_return(double) + expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :returns => [0], :timeout => timeout }).and_return(double) provider.run_action(:remove) expect(new_resource).to be_updated_by_last_action end diff --git a/spec/unit/provider/remote_file/sftp_spec.rb b/spec/unit/provider/remote_file/sftp_spec.rb index 7be507dc89..ddab1605f0 100644 --- a/spec/unit/provider/remote_file/sftp_spec.rb +++ b/spec/unit/provider/remote_file/sftp_spec.rb @@ -117,7 +117,7 @@ describe Chef::Provider::RemoteFile::SFTP do end context "and the URI specifies an alternate port" do - let(:uri) { URI.parse("ftp://conan:cthu1hu@opscode.com:8021/seattle.txt") } + let(:uri) { URI.parse("sftp://conan:cthu1hu@opscode.com:8021/seattle.txt") } it "should connect on an alternate port when one is provided" do expect(Net::SFTP).to receive(:start).with("opscode.com:8021", "conan", :password => "cthu1hu") @@ -127,10 +127,10 @@ describe Chef::Provider::RemoteFile::SFTP do end context "and the uri specifies a nested path" do - let(:uri) { URI.parse("ftp://conan:cthu1hu@opscode.com/the/whole/path/seattle.txt") } + let(:uri) { URI.parse("sftp://conan:cthu1hu@opscode.com/the/whole/path/seattle.txt") } it "should fetch the file from the correct path" do - expect(sftp).to receive(:download!).with("the/whole/path/seattle.txt", "/tmp/somedir/remote-file-sftp-backend-spec-test") + expect(sftp).to receive(:download!).with("/the/whole/path/seattle.txt", "/tmp/somedir/remote-file-sftp-backend-spec-test") fetcher.fetch end end diff --git a/spec/unit/provider/route_spec.rb b/spec/unit/provider/route_spec.rb index 7058d76590..03d1ad2477 100644 --- a/spec/unit/provider/route_spec.rb +++ b/spec/unit/provider/route_spec.rb @@ -230,13 +230,19 @@ describe Chef::Provider::Route do @run_context.resource_collection << Chef::Resource::Route.new("192.168.1.0/24 via 192.168.0.1") @run_context.resource_collection << Chef::Resource::Route.new("192.168.2.0/24 via 192.168.0.1") @run_context.resource_collection << Chef::Resource::Route.new("192.168.3.0/24 via 192.168.0.1") + @run_context.resource_collection << Chef::Resource::Route.new("Complex Route").tap do |r| + r.target "192.168.4.0" + r.gateway "192.168.0.1" + r.netmask "255.255.255.0" + end @provider.action = :add @provider.generate_config - expect(route_file.string.split("\n").size).to eq(3) + expect(route_file.string.split("\n").size).to eq(4) expect(route_file.string).to match(/^192\.168\.1\.0\/24 via 192\.168\.0\.1$/) expect(route_file.string).to match(/^192\.168\.2\.0\/24 via 192\.168\.0\.1$/) expect(route_file.string).to match(/^192\.168\.3\.0\/24 via 192\.168\.0\.1$/) + expect(route_file.string).to match(/^192\.168\.4\.0\/24 via 192\.168\.0\.1$/) end end end diff --git a/spec/unit/resource/chocolatey_package_spec.rb b/spec/unit/resource/chocolatey_package_spec.rb index e43803a65f..9b433045c1 100644 --- a/spec/unit/resource/chocolatey_package_spec.rb +++ b/spec/unit/resource/chocolatey_package_spec.rb @@ -64,4 +64,16 @@ describe Chef::Resource::ChocolateyPackage do resource.version(["1.2.3", "4.5.6"]) expect(resource.version).to eql(["1.2.3", "4.5.6"]) end + + it "the default returns should be 0" do + expect(resource.returns).to eql([0]) + end + + # Integer, Array + [ 0, [0, 48, 49] ].each do |val| + it "supports setting an alternate return value as a #{val.class}" do + resource.returns(val) + expect(resource.returns).to eql(val) + end + end end diff --git a/spec/unit/resource/dnf_package_spec.rb b/spec/unit/resource/dnf_package_spec.rb new file mode 100644 index 0000000000..0cc673d897 --- /dev/null +++ b/spec/unit/resource/dnf_package_spec.rb @@ -0,0 +1,99 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" +require "support/shared/unit/resource/static_provider_resolution" + +describe Chef::Resource::DnfPackage, "initialize" do + + static_provider_resolution( + resource: Chef::Resource::DnfPackage, + provider: Chef::Provider::Package::Dnf, + name: :dnf_package, + action: :install, + os: "linux", + platform_family: "rhel" + ) + +end + +describe Chef::Resource::DnfPackage, "arch" do + before(:each) do + @resource = Chef::Resource::DnfPackage.new("foo") + end + + it "should set the arch variable to whatever is passed in" do + @resource.arch("i386") + expect(@resource.arch).to eql(["i386"]) + end +end + +describe Chef::Resource::DnfPackage, "flush_cache" do + before(:each) do + @resource = Chef::Resource::DnfPackage.new("foo") + end + + it "should default the flush timing to false" do + flush_hash = { :before => false, :after => false } + expect(@resource.flush_cache).to eq(flush_hash) + end + + it "should allow you to set the flush timing with an array" do + flush_array = [ :before, :after ] + flush_hash = { :before => true, :after => true } + @resource.flush_cache(flush_array) + expect(@resource.flush_cache).to eq(flush_hash) + end + + it "should allow you to set the flush timing with a hash" do + flush_hash = { :before => true, :after => true } + @resource.flush_cache(flush_hash) + expect(@resource.flush_cache).to eq(flush_hash) + end + + it "should allow 'true' for flush_cache" do + @resource.flush_cache(true) + expect(@resource.flush_cache).to eq({ before: true, after: true }) + end + + it "should allow 'false' for flush_cache" do + @resource.flush_cache(false) + expect(@resource.flush_cache).to eq({ before: false, after: false }) + end + + it "should allow ':before' for flush_cache" do + @resource.flush_cache(:before) + expect(@resource.flush_cache).to eq({ before: true, after: false }) + end + + it "should allow ':after' for flush_cache" do + @resource.flush_cache(:after) + expect(@resource.flush_cache).to eq({ before: false, after: true }) + end +end + +describe Chef::Resource::DnfPackage, "allow_downgrade" do + before(:each) do + @resource = Chef::Resource::DnfPackage.new("foo") + end + + it "should allow you to specify whether allow_downgrade is true or false" do + Chef::Config[:treat_deprecation_warnings_as_errors] = false + expect { @resource.allow_downgrade true }.not_to raise_error + expect { @resource.allow_downgrade false }.not_to raise_error + end +end diff --git a/spec/unit/resource/dsc_resource_spec.rb b/spec/unit/resource/dsc_resource_spec.rb index b610c262cc..b687811392 100644 --- a/spec/unit/resource/dsc_resource_spec.rb +++ b/spec/unit/resource/dsc_resource_spec.rb @@ -18,6 +18,7 @@ require "spec_helper" describe Chef::Resource::DscResource do let(:dsc_test_resource_name) { "DSCTest" } + let(:dsc_test_resource_module_version) { "2.7.2" } let(:dsc_test_property_name) { :DSCTestProperty } let(:dsc_test_property_value) { "DSCTestValue" } let(:dsc_test_reboot_action) { :reboot_now } @@ -53,6 +54,11 @@ describe Chef::Resource::DscResource do expect(dsc_test_resource.module_name).to eq(dsc_test_resource_name) end + it "allows the module_version attribute to be set" do + dsc_test_resource.module_version(dsc_test_resource_module_version) + expect(dsc_test_resource.module_version).to eq(dsc_test_resource_module_version) + end + it "allows the reboot_action attribute to be set" do dsc_test_resource.reboot_action(dsc_test_reboot_action) expect(dsc_test_resource.reboot_action).to eq(dsc_test_reboot_action) diff --git a/spec/unit/resource/yum_package_spec.rb b/spec/unit/resource/yum_package_spec.rb index dd0d3ae928..bc2d19d50e 100644 --- a/spec/unit/resource/yum_package_spec.rb +++ b/spec/unit/resource/yum_package_spec.rb @@ -65,6 +65,26 @@ describe Chef::Resource::YumPackage, "flush_cache" do @resource.flush_cache(flush_hash) expect(@resource.flush_cache).to eq(flush_hash) end + + it "should allow 'true' for flush_cache" do + @resource.flush_cache(true) + expect(@resource.flush_cache).to eq({ before: true, after: true }) + end + + it "should allow 'false' for flush_cache" do + @resource.flush_cache(false) + expect(@resource.flush_cache).to eq({ before: false, after: false }) + end + + it "should allow ':before' for flush_cache" do + @resource.flush_cache(:before) + expect(@resource.flush_cache).to eq({ before: true, after: false }) + end + + it "should allow ':after' for flush_cache" do + @resource.flush_cache(:after) + expect(@resource.flush_cache).to eq({ before: false, after: true }) + end end describe Chef::Resource::YumPackage, "allow_downgrade" do diff --git a/spec/unit/win32/error_spec.rb b/spec/unit/win32/error_spec.rb new file mode 100644 index 0000000000..e8b6d5af6a --- /dev/null +++ b/spec/unit/win32/error_spec.rb @@ -0,0 +1,67 @@ +# +# Author:: Aliasgar Batterywala (aliasgar.batterywala@msystechnologies.com) +# Copyright:: Copyright 2017, 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" +if Chef::Platform.windows? + require "chef/win32/error" + require "chef/win32/api/error" +end + +describe "Chef::Win32::Error", :windows_only do + describe "self.raise!" do + context "code is not passed to the raise! method" do + context "last error received is user_not_found" do + it "raises UserIDNotFound exception" do + expect(Chef::ReservedNames::Win32::Error).to receive(:get_last_error).and_return( + Chef::ReservedNames::Win32::API::Error::ERROR_USER_NOT_FOUND + ) + expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip) + expect { Chef::ReservedNames::Win32::Error.raise! }.to raise_error Chef::Exceptions::UserIDNotFound + end + end + + context "last error received is not user_not_found" do + it "raises Win32APIError exception" do + expect(Chef::ReservedNames::Win32::Error).to receive(:get_last_error).and_return( + Chef::ReservedNames::Win32::API::Error::ERROR_BAD_USERNAME + ) + expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip).and_return("Bad Username") + expect { Chef::ReservedNames::Win32::Error.raise! }.to raise_error Chef::Exceptions::Win32APIError + end + end + end + + context "code is passed to the raise! method" do + context "last error received is user_not_found" do + it "raises UserIDNotFound exception" do + expect(Chef::ReservedNames::Win32::Error).to_not receive(:get_last_error) + expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip) + expect { Chef::ReservedNames::Win32::Error.raise! nil, Chef::ReservedNames::Win32::API::Error::ERROR_USER_NOT_FOUND }.to raise_error Chef::Exceptions::UserIDNotFound + end + end + + context "last error received is not user_not_found" do + it "raises Win32APIError exception" do + expect(Chef::ReservedNames::Win32::Error).to_not receive(:get_last_error) + expect(Chef::ReservedNames::Win32::Error).to receive_message_chain(:format_message, :strip).and_return("Bad Username") + expect { Chef::ReservedNames::Win32::Error.raise! nil, Chef::ReservedNames::Win32::API::Error::ERROR_BAD_USERNAME }.to raise_error Chef::Exceptions::Win32APIError + end + end + end + end +end diff --git a/spec/unit/win32/security_spec.rb b/spec/unit/win32/security_spec.rb new file mode 100644 index 0000000000..1c755061ce --- /dev/null +++ b/spec/unit/win32/security_spec.rb @@ -0,0 +1,66 @@ +# +# Author:: Aliasgar Batterywala (aliasgar.batterywala@msystechnologies.com) +# Copyright:: Copyright 2017, 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" +if Chef::Platform.windows? + require "chef/win32/error" + require "chef/win32/security" + require "chef/win32/api/error" +end + +describe "Chef::Win32::Security", :windows_only do + describe "self.get_named_security_info" do + context "when HR result is ERROR_SUCCESS" do + it "does not raise the exception" do + expect(Chef::ReservedNames::Win32::Security).to receive(:GetNamedSecurityInfoW).and_return( + Chef::ReservedNames::Win32::API::Error::ERROR_SUCCESS + ) + expect { Chef::ReservedNames::Win32::Security.get_named_security_info "/temp_path" }.to_not raise_error + end + end + + context "when HR result is not ERROR_SUCCESS and not ERROR_USER_NOT_FOUND" do + it "raises Win32APIError exception" do + expect(Chef::ReservedNames::Win32::Security).to receive(:GetNamedSecurityInfoW).and_return( + Chef::ReservedNames::Win32::API::Error::ERROR_INVALID_ACCESS + ) + expect { Chef::ReservedNames::Win32::Security.get_named_security_info "/temp_path" }.to raise_error Chef::Exceptions::Win32APIError + end + end + end + + describe "self.set_named_security_info" do + context "when HR result is ERROR_SUCCESS" do + it "does not raise the exception" do + expect(Chef::ReservedNames::Win32::Security).to receive(:SetNamedSecurityInfoW).and_return( + Chef::ReservedNames::Win32::API::Error::ERROR_SUCCESS + ) + expect { Chef::ReservedNames::Win32::Security.set_named_security_info "/temp_path", :SE_FILE_OBJECT, {} }.to_not raise_error + end + end + + context "when HR result is not ERROR_SUCCESS but it is ERROR_USER_NOT_FOUND" do + it "raises UserIDNotFound exception" do + expect(Chef::ReservedNames::Win32::Security).to receive(:SetNamedSecurityInfoW).and_return( + Chef::ReservedNames::Win32::API::Error::ERROR_USER_NOT_FOUND + ) + expect { Chef::ReservedNames::Win32::Security.set_named_security_info "/temp_path", :SE_FILE_OBJECT, {} }.to raise_error Chef::Exceptions::Chef::Exceptions::UserIDNotFound + end + end + end +end diff --git a/version_policy.rb b/version_policy.rb index 5621ea43ff..a16e7ad500 100644 --- a/version_policy.rb +++ b/version_policy.rb @@ -21,6 +21,7 @@ OMNIBUS_OVERRIDES = { ## according to comment in omnibus-sw, latest versions don't work on solaris # https://github.com/chef/omnibus-software/blob/aefb7e79d29ca746c3f843673ef5e317fa3cba54/config/software/libtool.rb#L23 :bundler => "1.12.5", # until we figure out how to work with 1.13.0 + :rainbow => "2.1.0", # Currently pinned until rubygems is updated "libffi" => "3.2.1", "libiconv" => "1.14", "liblzma" => "5.2.2", |