diff options
author | Dmitry Shestoperov <dshestoperov@sitespect.com> | 2018-02-13 08:39:27 -0500 |
---|---|---|
committer | Dmitry Shestoperov <dshestoperov@sitespect.com> | 2018-02-13 08:39:27 -0500 |
commit | 29748ede0cd6fa3799a2f8c4912f037a31f1eeea (patch) | |
tree | 8ba342e1f6d6dfd00a800ed4e55af23fdac80f2b | |
parent | 68e9f4618bc6432023f8327cfce775618806fa9e (diff) | |
parent | 493947028e8560e86a014aced4273f509a678c31 (diff) | |
download | chef-29748ede0cd6fa3799a2f8c4912f037a31f1eeea.tar.gz |
Merge upstream
71 files changed, 1182 insertions, 252 deletions
@@ -168,3 +168,7 @@ Peter Burkholder <pburkholder@chef.io> Peter Burkholder <peterb@getchef.com> # JJ Ashgar JJ Asghar <jj@chef.io> JJ Asghar <jj@getchef.com> + +# Tim Smith +Tim Smith <tsmith@chef.io> Tim Smith <tim@cozy.co> +Tim Smith <tsmith@chef.io> Tim Smith <tsmith84@gmail.co> diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f0e6f4c5e..66ca41ce14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,39 +1,79 @@ <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ --> -<!-- latest_release 13.5.6 --> -## [v13.5.6](https://github.com/chef/chef/tree/v13.5.6) (2017-09-29) +<!-- latest_release 13.6.7 --> +## [v13.6.7](https://github.com/chef/chef/tree/v13.6.7) (2017-11-15) #### Merged Pull Requests -- Bump InSpec to v1.40.0 [#6460](https://github.com/chef/chef/pull/6460) ([adamleff](https://github.com/adamleff)) +- Change a useradd_spec test for RHEL >= 6.8 and >= 7.3 [#6555](https://github.com/chef/chef/pull/6555) ([jeremiahsnapp](https://github.com/jeremiahsnapp)) <!-- latest_release --> -<!-- release_rollup since=12.21.14 --> -### Changes since 12.21.14 release +<!-- release_rollup since=13.6.4 --> +### Changes since 13.6.4 release #### Merged Pull Requests -- Bump InSpec to v1.40.0 [#6460](https://github.com/chef/chef/pull/6460) ([adamleff](https://github.com/adamleff)) <!-- 13.5.6 --> -- Force encoding to UTF_8 in chef-shell to prevent failures [#6447](https://github.com/chef/chef/pull/6447) ([tas50](https://github.com/tas50)) <!-- 13.5.5 --> -- only warn about skipping sync once [#6454](https://github.com/chef/chef/pull/6454) ([Happycoil](https://github.com/Happycoil)) <!-- 13.5.4 --> -- Replace which apt-get check with simple debian check in apt resources [#6409](https://github.com/chef/chef/pull/6409) ([tas50](https://github.com/tas50)) <!-- 13.4.25 --> -- Quiet the output of the zypper refresh and add force [#6408](https://github.com/chef/chef/pull/6408) ([tas50](https://github.com/tas50)) <!-- 13.4.26 --> -- Remove unused requires in yum_repository [#6413](https://github.com/chef/chef/pull/6413) ([tas50](https://github.com/tas50)) <!-- 13.4.27 --> -- Open apt resources up to prevent breaking change [#6417](https://github.com/chef/chef/pull/6417) ([tas50](https://github.com/tas50)) <!-- 13.4.28 --> -- Don't catch SIGCHLD from dnf_helper.py [#6416](https://github.com/chef/chef/pull/6416) ([nemith](https://github.com/nemith)) <!-- 13.4.29 --> -- Add throttle and metalink options to yum_repository [#6431](https://github.com/chef/chef/pull/6431) ([tas50](https://github.com/tas50)) <!-- 13.4.31 --> -- Fix Knife search ID only option to actually filter result set [#6438](https://github.com/chef/chef/pull/6438) ([dimsh99](https://github.com/dimsh99)) <!-- 13.4.32 --> -- Update dependencies to pull in InSpec v1.39.1 [#6440](https://github.com/chef/chef/pull/6440) ([adamleff](https://github.com/adamleff)) <!-- 13.4.34 --> -- Only accept MM/DD/YYYY for windows_task start_day [#6434](https://github.com/chef/chef/pull/6434) ([jaym](https://github.com/jaym)) <!-- 13.4.35 --> -- fix password property is sensitive for mount resource [#6442](https://github.com/chef/chef/pull/6442) ([dimsh99](https://github.com/dimsh99)) <!-- 13.4.36 --> +- Change a useradd_spec test for RHEL >= 6.8 and >= 7.3 [#6555](https://github.com/chef/chef/pull/6555) ([jeremiahsnapp](https://github.com/jeremiahsnapp)) <!-- 13.6.7 --> +- replace deprecated Dir.exists? with Dir.exist? [#6583](https://github.com/chef/chef/pull/6583) ([thomasdziedzic](https://github.com/thomasdziedzic)) <!-- 13.6.6 --> +- Add ohai_time to minimal_ohai filter [#6584](https://github.com/chef/chef/pull/6584) ([btm](https://github.com/btm)) <!-- 13.6.5 --> <!-- release_rollup --> <!-- latest_stable_release --> -## [v12.21.14](https://github.com/chef/chef/tree/v12.21.14) (2017-09-27) +## [v13.6.4](https://github.com/chef/chef/tree/v13.6.4) (2017-11-06) + +#### Merged Pull Requests +- [MSYS-492]Add missing functional tests for users [#6425](https://github.com/chef/chef/pull/6425) ([harikesh-kolekar](https://github.com/harikesh-kolekar)) +- Fix the invalid version comparison in apt/dpkg providers [#6558](https://github.com/chef/chef/pull/6558) ([tas50](https://github.com/tas50)) +- Fix the invalid version comparison of apt packages. [#6554](https://github.com/chef/chef/pull/6554) ([komazarari](https://github.com/komazarari)) +- Bump openssl and rubygems to latest [#6568](https://github.com/chef/chef/pull/6568) ([tas50](https://github.com/tas50)) <!-- latest_stable_release --> +## [v13.6.0](https://github.com/chef/chef/tree/v13.6.0) (2017-10-30) + +#### Merged Pull Requests +- Bump InSpec to v1.40.0 [#6460](https://github.com/chef/chef/pull/6460) ([adamleff](https://github.com/adamleff)) +- Force encoding to UTF_8 in chef-shell to prevent failures [#6447](https://github.com/chef/chef/pull/6447) ([tas50](https://github.com/tas50)) +- Only warn about skipping sync once [#6454](https://github.com/chef/chef/pull/6454) ([Happycoil](https://github.com/Happycoil)) +- Import the zypper GPG key before templating the repo [#6410](https://github.com/chef/chef/pull/6410) ([tas50](https://github.com/tas50)) +- Fixes to package upgrade behaviour [#6428](https://github.com/chef/chef/pull/6428) ([jonlives](https://github.com/jonlives)) +- Tweak the knife banners for multi-arg commands. [#6466](https://github.com/chef/chef/pull/6466) ([coderanger](https://github.com/coderanger)) +- dnf_resource: be more specific for rhel packages [#6435](https://github.com/chef/chef/pull/6435) ([NaomiReeves](https://github.com/NaomiReeves)) +- Prevent creation of data bags named node, role, client or environment [#6469](https://github.com/chef/chef/pull/6469) ([sanditiffin](https://github.com/sanditiffin)) +- Remove cookbook_artifacts from CHEF_11_OSS_STATIC_OBJECTS [#6478](https://github.com/chef/chef/pull/6478) ([itmustbejj](https://github.com/itmustbejj)) +- Add allow_downgrade to zypper_package resource [#6476](https://github.com/chef/chef/pull/6476) ([yeoldegrove](https://github.com/yeoldegrove)) +- Don't spin in powershell module that launches chef processes [#6481](https://github.com/chef/chef/pull/6481) ([ksubrama](https://github.com/ksubrama)) +- Sleep for another interval after handling SIGHUP [#6461](https://github.com/chef/chef/pull/6461) ([grekasius](https://github.com/grekasius)) +- Support new CriticalOhaiPlugins [#6486](https://github.com/chef/chef/pull/6486) ([jaymzh](https://github.com/jaymzh)) +- Package: only RHEL >= 8 and Fedora >= 22 get dnf [#6490](https://github.com/chef/chef/pull/6490) ([lamont-granquist](https://github.com/lamont-granquist)) +- Windows: Added :none frequency to windows_task resource [#6394](https://github.com/chef/chef/pull/6394) ([NAshwini](https://github.com/NAshwini)) +- Fix rebooter for solaris and background reboots [#6497](https://github.com/chef/chef/pull/6497) ([lamont-granquist](https://github.com/lamont-granquist)) +- Added parser for DSC configuration [#6473](https://github.com/chef/chef/pull/6473) ([piyushawasthi](https://github.com/piyushawasthi)) +- Add array support for choco pkg from artifactory [#6437](https://github.com/chef/chef/pull/6437) ([dheerajd-msys](https://github.com/dheerajd-msys)) +- Bump dependencies to pull in new InSpec [#6511](https://github.com/chef/chef/pull/6511) ([adamleff](https://github.com/adamleff)) +- Fix remote_file with UNC paths failing [#6510](https://github.com/chef/chef/pull/6510) ([tas50](https://github.com/tas50)) +- Deprecate the deploy resource and family [#6468](https://github.com/chef/chef/pull/6468) ([coderanger](https://github.com/coderanger)) +- Include Ohai 13.6 [#6521](https://github.com/chef/chef/pull/6521) ([btm](https://github.com/btm)) +- Use the latest libxml2, libxslt, libyaml, and openssl [#6520](https://github.com/chef/chef/pull/6520) ([tas50](https://github.com/tas50)) +- Pull in the latest libiconv and nokogiri [#6532](https://github.com/chef/chef/pull/6532) ([tas50](https://github.com/tas50)) + +## [v13.5.3](https://github.com/chef/chef/tree/v13.5.3) (2017-10-03) + +#### Merged Pull Requests +- Fix password property is sensitive for mount resource [#6442](https://github.com/chef/chef/pull/6442) ([dimsh99](https://github.com/dimsh99)) +- Only accept MM/DD/YYYY for windows_task start_day [#6434](https://github.com/chef/chef/pull/6434) ([jaym](https://github.com/jaym)) +- Update dependencies to pull in InSpec v1.39.1 [#6440](https://github.com/chef/chef/pull/6440) ([adamleff](https://github.com/adamleff)) +- Fix Knife search ID only option to actually filter result set [#6438](https://github.com/chef/chef/pull/6438) ([dimsh99](https://github.com/dimsh99)) +- Add throttle and metalink options to yum_repository [#6431](https://github.com/chef/chef/pull/6431) ([tas50](https://github.com/tas50)) +- Don't catch SIGCHLD from dnf_helper.py [#6416](https://github.com/chef/chef/pull/6416) ([nemith](https://github.com/nemith)) +- Open apt resources up to prevent breaking change [#6417](https://github.com/chef/chef/pull/6417) ([tas50](https://github.com/tas50)) +- Remove unused requires in yum_repository [#6413](https://github.com/chef/chef/pull/6413) ([tas50](https://github.com/tas50)) +- Quiet the output of the zypper refresh and add force [#6408](https://github.com/chef/chef/pull/6408) ([tas50](https://github.com/tas50)) +- Replace which apt-get check with simple debian check in apt resources [#6409](https://github.com/chef/chef/pull/6409) ([tas50](https://github.com/tas50)) + +## [v12.21.14](https://github.com/chef/chef/tree/v12.21.14) (2017-09-27) + ## [v13.4.24](https://github.com/chef/chef/tree/v13.4.24) (2017-09-14) #### Merged Pull Requests -- MSYS-656 - fixed dsc_script for WMF5 [#6383](https://github.com/chef/chef/pull/6383) ([piyushawasthi](https://github.com/piyushawasthi)) -- [MSYS-594] windows_task resource is not idempotent when specifying start_time and start_day [#6312](https://github.com/chef/chef/pull/6312) ([harikesh-kolekar](https://github.com/harikesh-kolekar)) +- Fixed dsc_script for WMF5 [#6383](https://github.com/chef/chef/pull/6383) ([piyushawasthi](https://github.com/piyushawasthi)) +- windows_task resource is not idempotent when specifying start_time and start_day [#6312](https://github.com/chef/chef/pull/6312) ([harikesh-kolekar](https://github.com/harikesh-kolekar)) - Allow specifying default gateway on RHEL/Centos [#6386](https://github.com/chef/chef/pull/6386) ([tomdoherty](https://github.com/tomdoherty)) - Use ruby 2.4.2 to addess multiple security vulnerabilities [#6404](https://github.com/chef/chef/pull/6404) ([thommay](https://github.com/thommay)) @@ -51,7 +91,7 @@ - Bump Bundler version to 1.15.4 [#6349](https://github.com/chef/chef/pull/6349) ([jakauppila](https://github.com/jakauppila)) - dnf_provider: be more specific when we provide `package` [#6351](https://github.com/chef/chef/pull/6351) ([jaymzh](https://github.com/jaymzh)) - Speed up immutabilization [#6355](https://github.com/chef/chef/pull/6355) ([lamont-granquist](https://github.com/lamont-granquist)) -- node attributes: remove useless dup in merge_all [#6356](https://github.com/chef/chef/pull/6356) ([lamont-granquist](https://github.com/lamont-granquist)) +- Node attributes: remove useless dup in merge_all [#6356](https://github.com/chef/chef/pull/6356) ([lamont-granquist](https://github.com/lamont-granquist)) - Link to the knife docs in both places where we error on editor [#6363](https://github.com/chef/chef/pull/6363) ([tas50](https://github.com/tas50)) - Bump rubygems to 2.6.13 [#6365](https://github.com/chef/chef/pull/6365) ([lamont-granquist](https://github.com/lamont-granquist)) - Ship chef-vault in the omnibus package [#6370](https://github.com/chef/chef/pull/6370) ([thommay](https://github.com/thommay)) @@ -59,20 +99,18 @@ - Immutablize properly as we deep merge [#6362](https://github.com/chef/chef/pull/6362) ([lamont-granquist](https://github.com/lamont-granquist)) - Alternate user local logon authentication for remote_file resource [#5832](https://github.com/chef/chef/pull/5832) ([NimishaS](https://github.com/NimishaS)) - Add support for specifying ETHTOOL_OPTS in the ifconfig resource [#6384](https://github.com/chef/chef/pull/6384) ([tomdoherty](https://github.com/tomdoherty)) -- Cleanup the current changelog [#6387](https://github.com/chef/chef/pull/6387) ([tas50](https://github.com/tas50)) ## [v13.3.42](https://github.com/chef/chef/tree/v13.3.42) (2017-08-16) #### Merged Pull Requests -- Update Expeditor config to use new Merge and Artifact Actions [#6287](https://github.com/chef/chef/pull/6287) ([tduffield](https://github.com/tduffield)) - Apt: Add apt_preference resource from apt cookbooks [#5529](https://github.com/chef/chef/pull/5529) ([tas50](https://github.com/tas50)) - Fix typos [#6298](https://github.com/chef/chef/pull/6298) ([akitada](https://github.com/akitada)) - Set explicit page size for every search request [#6299](https://github.com/chef/chef/pull/6299) ([stevendanna](https://github.com/stevendanna)) - Add .dockerignore to reduce size of resulting images [#6296](https://github.com/chef/chef/pull/6296) ([tduffield](https://github.com/tduffield)) - Fix git command in DCO sign-off example [#6306](https://github.com/chef/chef/pull/6306) ([edmorley](https://github.com/edmorley)) -- add option to enable unprivileged symlink creation on windows [#6236](https://github.com/chef/chef/pull/6236) ([svmastersamurai](https://github.com/svmastersamurai)) +- Add option to enable unprivileged symlink creation on windows [#6236](https://github.com/chef/chef/pull/6236) ([svmastersamurai](https://github.com/svmastersamurai)) - Bump omnibus-software version [#6310](https://github.com/chef/chef/pull/6310) ([thommay](https://github.com/thommay)) -- throw readable errors if multiple dsc resources are found [#6307](https://github.com/chef/chef/pull/6307) ([Happycoil](https://github.com/Happycoil)) +- Throw readable errors if multiple dsc resources are found [#6307](https://github.com/chef/chef/pull/6307) ([Happycoil](https://github.com/Happycoil)) - Add zypper_repository resource [#5948](https://github.com/chef/chef/pull/5948) ([tas50](https://github.com/tas50)) - Pull in Ohai 13.3 [#6319](https://github.com/chef/chef/pull/6319) ([tas50](https://github.com/tas50)) - Maintain compat with old zypper_repo resource used in cookbooks [#6318](https://github.com/chef/chef/pull/6318) ([tas50](https://github.com/tas50)) @@ -85,12 +123,11 @@ - Added username/password validation for elevated option [\#6293](https://github.com/chef/chef/pull/6293) ([NimishaS](https://github.com/NimishaS)) - Bump mixlib-shellout for \#6271 [\#6285](https://github.com/chef/chef/pull/6285) ([btm](https://github.com/btm)) -- Use new Expeditor config format [\#6272](https://github.com/chef/chef/pull/6272) ([tduffield](https://github.com/tduffield)) - Added :elevated option for powershell\_script resource [\#6271](https://github.com/chef/chef/pull/6271) ([NimishaS](https://github.com/NimishaS)) - Make mount idempotent on Aix [\#6213](https://github.com/chef/chef/pull/6213) ([NAshwini](https://github.com/NAshwini)) - Allow windows\_task create action to update tasks. [\#6193](https://github.com/chef/chef/pull/6193) ([harikesh-kolekar](https://github.com/harikesh-kolekar)) - Use socketless local mode by default [\#6177](https://github.com/chef/chef/pull/6177) ([coderanger](https://github.com/coderanger)) -- convert breakpoint resource to a custom resource [\#6176](https://github.com/chef/chef/pull/6176) ([lamont-granquist](https://github.com/lamont-granquist)) +- Convert breakpoint resource to a custom resource [\#6176](https://github.com/chef/chef/pull/6176) ([lamont-granquist](https://github.com/lamont-granquist)) - Make non-legacy solo use socketless mode [\#6174](https://github.com/chef/chef/pull/6174) ([coderanger](https://github.com/coderanger)) - Prefer Systemd with sysvinit script over Upstart for service provider [\#6157](https://github.com/chef/chef/pull/6157) ([shortdudey123](https://github.com/shortdudey123)) diff --git a/Dockerfile b/Dockerfile index 51e1669a26..4b3c3f5e67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM busybox MAINTAINER Chef Software, Inc. <docker@chef.io> ARG CHANNEL=stable -ARG VERSION=12.21.14 +ARG VERSION=13.6.4 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 ee88c25abc..9f22780e2c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,7 +8,7 @@ GIT GIT remote: https://github.com/rubysec/bundler-audit.git - revision: 6e2e298aebb0707a1b62c08c005335ecd130aa66 + revision: 06e6077aaaed3744915b1dda71effeea2ea41751 specs: bundler-audit (0.6.0) bundler (~> 1.2) @@ -17,10 +17,10 @@ GIT PATH remote: . specs: - chef (13.5.6) + chef (13.6.7) addressable bundler (>= 1.10) - chef-config (= 13.5.6) + chef-config (= 13.6.7) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -47,10 +47,10 @@ PATH specinfra (~> 2.10) syslog-logger (~> 1.6) uuidtools (~> 2.1.5) - chef (13.5.6-universal-mingw32) + chef (13.6.7-universal-mingw32) addressable bundler (>= 1.10) - chef-config (= 13.5.6) + chef-config (= 13.6.7) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -92,7 +92,7 @@ PATH PATH remote: chef-config specs: - chef-config (13.5.6) + chef-config (13.6.7) addressable fuzzyurl mixlib-config (~> 2.0) @@ -106,7 +106,7 @@ GEM mixlib-cli (~> 1.4) mixlib-shellout (~> 2.0) ast (2.3.0) - backports (3.8.0) + backports (3.10.3) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) blankslate (2.1.2.4) @@ -158,13 +158,13 @@ GEM ffi (>= 1.0.1) gyoku (1.3.1) builder (>= 2.1.2) - hashdiff (0.3.6) + hashdiff (0.3.7) hashie (3.5.6) highline (1.7.8) htmlentities (4.3.4) httpclient (2.8.3) iniparse (1.4.4) - inspec (1.40.0) + inspec (1.42.3) addressable (~> 2.4) faraday (>= 0.9.0) hashie (~> 3.4) @@ -224,7 +224,7 @@ GEM nori (2.6.0) octokit (4.7.0) sawyer (~> 0.8.0, >= 0.5.3) - ohai (13.5.0) + ohai (13.6.0) chef-config (>= 12.5.0.alpha.1, < 14) ffi (~> 1.9) ffi-yajl (~> 2.2) @@ -244,7 +244,7 @@ GEM plist (3.3.0) powerpack (0.1.1) proxifier (1.0.3) - pry (0.11.1) + pry (0.11.2) coderay (~> 1.1.0) method_source (~> 0.9.0) pry-byebug (3.5.0) @@ -264,22 +264,22 @@ GEM rake rake (12.1.0) rb-readline (0.5.5) - rspec (3.6.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-core (3.6.0) - rspec-support (~> 3.6.0) - rspec-expectations (3.6.0) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.0) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) + rspec-support (~> 3.7.0) rspec-its (1.2.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.6.0) + rspec-mocks (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-support (3.6.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.0) rspec_junit_formatter (0.2.3) builder (< 4) rspec-core (>= 2, < 4, != 2.12.0) @@ -300,7 +300,7 @@ GEM addressable (>= 2.3.5, < 2.6) faraday (~> 0.8, < 1.0) semverse (2.0.0) - serverspec (2.41.0) + serverspec (2.41.3) multi_json rspec (~> 3.0) rspec-its @@ -312,7 +312,7 @@ GEM simplecov-html (~> 0.10.0) simplecov-html (0.10.2) slop (3.6.0) - specinfra (2.72.0) + specinfra (2.72.1) net-scp net-ssh (>= 2.7, < 5.0) net-telnet @@ -345,7 +345,7 @@ GEM ethon (>= 0.8.0) unicode-display_width (1.3.0) uuidtools (2.1.5) - webmock (3.0.1) + webmock (3.1.0) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff @@ -379,7 +379,7 @@ GEM logging (>= 1.6.1, < 3.0) nori (~> 2.0) rubyntlm (~> 0.6.0, >= 0.6.1) - winrm-fs (1.0.2) + winrm-fs (1.1.0) erubis (~> 2.7) logging (>= 1.6.1, < 3.0) rubyzip (~> 1.1) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3ffac73161..4265b87494 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,72 @@ _This file holds "in progress" release notes for the current release under development and is intended for consumption by the Chef Documentation team. Please see <https://docs.chef.io/release_notes.html> for the official Chef release notes._ +# Chef Client Release Notes 13.6.4: + +## Bugfixes + + - Resolved a regression in 13.6.0 that prevented upgrading packages on Debian/Ubuntu when the package name contained a tilde. + +## Security Updates + +- OpenSSL has been upgraded to 1.0.2m to resolve CVE-2017-3735 and CVE-2017-3736 +- RubyGems has been upgraded to 2.6.14 to resolve CVE-2017-0903 + +# Chef Client Release Notes 13.6: + +## `deploy` Resource Is Deprecated + +The `deploy` resource (and its alter ego `deploy_revision`) have been deprecated, +to be removed in Chef 14. This is being done because this resource is considered +overcomplicated and error-prone in the modern Chef ecosystem. A compatibility +cookbook will be available to help users migrate during the Chef 14 release +cycle. See [the deprecation documentation](https://docs.chef.io/deprecations_deploy_resource.html) +for more information. + +## zypper\_package supports package downgrades + +`zypper_package` now supports downgrading installed packages with the +`allow_downgrade` property. + +## InSpec updated to 1.42.3 + +## Reserve certain Data Bag names + +It's no longer possible to create data bags named `node`, `role`, +`client`, or `environment`. Existing data bags will continue to work as +before. + +## Properly use yum on RHEL 7 + +If both dnf and yum were installed, in some circumstances the yum +provider might choose to run dnf, which is not what we intended it to +do. It now properly runs yum, all the time. + +## Ohai 13.6 Release Notes: + +### Critical Plugins + +Users can now specify a list of plugins which are `critical`. Critical plugins will cause Ohai to fail if they do not run successfully (and thus cause a Chef run using Ohai to fail). The syntax for this is: + +``` +ohai.critical_plugins << :Filesystem +``` + +### Filesystem now has a `allow_partial_data` configuration option + +The Filesystem plugin now has a `allow_partial_data` configuration option. If set, the filesystem will return whatever data it can even if some commands it ran failed. + +### Rackspace detection on Windows + +Windows nodes running on Rackspace will now properly detect themselves as running on Rackspace without a hint file. + +### Package data on Amazon Linux + +The Packages plugin now supports gathering packages data on Amazon Linux + +### Deprecation updates + +In Ohai 13 we replaced the filesystem and cloud plugins with the filesystem2 and cloud_v2 plugins. To maintain compatibility with users of the previous V2 plugins we write data to both locations. We had originally planned to continue writing data to both locations until Chef 15. Instead due to the large amount of duplicate node data this introduces we are updating OHAI-11 and OHAI-12 deprecations to remove node['cloud_v2'] and node['filesystem2'] with the release of Chef 14 in April 2018. + # Chef Client Release Notes 13.5: ## Mount's password property is now marked as sensitive @@ -74,7 +141,7 @@ It is now possible to set `ETHTOOL_OPTS`, `BONDING_OPTS`, `MASTER` and **Platforms:** Fedora, RHEL, Amazon Linux Whether the interface is controlled by the channel bonding interface defined by `master`, above. - + ## Chef Vault is now included Chef Client 13.4 now includes the `chef-vault` gem, making it easier for @@ -1 +1 @@ -13.5.6
\ No newline at end of file +13.6.7
\ No newline at end of file diff --git a/chef-config/lib/chef-config/path_helper.rb b/chef-config/lib/chef-config/path_helper.rb index e8a576c84f..c011c4f18a 100644 --- a/chef-config/lib/chef-config/path_helper.rb +++ b/chef-config/lib/chef-config/path_helper.rb @@ -235,7 +235,7 @@ module ChefConfig paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path } # Filter out duplicate paths and paths that don't exist. - valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path.force_encoding("utf-8")) } + valid_paths = paths.select { |home_path| home_path && Dir.exist?(home_path.force_encoding("utf-8")) } valid_paths = valid_paths.uniq # Join all optional path elements at the end. diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb index f144a36c63..71a7611ca1 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 = "13.5.6" + VERSION = "13.6.7" end # diff --git a/distro/powershell/chef/chef.psm1 b/distro/powershell/chef/chef.psm1 index 9196d62e6c..1a5e2cc5eb 100644 --- a/distro/powershell/chef/chef.psm1 +++ b/distro/powershell/chef/chef.psm1 @@ -282,6 +282,24 @@ function Run-ExecutableAndWait($AppPath, $ArgumentString) { break } } + } else { + # For some reason, you can't read from the read-end of the read-pipe before the write end has started + # to write. Otherwise the process just blocks forever and never returns from the read. So we peek + # at the pipe until there is something. But don't peek too eagerly. This is stupid stupid stupid. + # There must be a way to do this without having to peek at a pipe first but I have not found it. + # + # Note to the future intrepid soul who wants to fix this: + # 0) This is related to unreasonable CPU usage by the wrapper PS script on a 1 VCPU VM (either Hyper-V + # or VirtualBox) running a consumer Windows SKU (Windows 10 for example...). Test it there. + # 1) Maybe this entire script is unnecessary and the bugs mentioned below have been fixed or don't need + # to be supported. + # 2) The server and consumer windows schedulers have different defaults. I had a hard time reproducing + # any issue on a win 2008 on win 2012 server default setup. See the "foreground application scheduler + # priority" setting to see if it's relevant. + # 3) This entire endeavor is silly anyway - why are we reimplementing process forking all over? Maybe try + # to get the folks above to accept patches instead of extending this crazy script. + Start-Sleep -s 1 + # Start-Sleep -m 100 } if ($global:LASTEXITCODE -ne [Chef.Kernel32]::STILL_ACTIVE) { @@ -434,9 +452,12 @@ Export-ModuleMember -function chef-solo Export-ModuleMember -function chef-windows-service Export-ModuleMember -function knife -# To debug this module, uncomment the line below and then run the following. +# To debug this module, uncomment the line below # Export-ModuleMember -function Run-RubyCommand + +# Then run the following to reload the module. Use puts_argv as a helpful debug executable. # Remove-Module chef # Import-Module chef -# "puts ARGV" | Out-File C:\opscode\chef\bin\puts_args +# "puts ARGV" | Out-File C:\opscode\chef\bin\puts_args -Encoding ASCII +# Copy-Item C:\opscode\chef\bin\ohai.bat C:\opscode\chef\bin\puts_args.bat # Run-RubyCommand puts_args 'Here' "are" some '"very interesting"' 'arguments[to]' "`"try out`"" diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb index ae16777cb6..32530925d5 100644 --- a/lib/chef/application/client.rb +++ b/lib/chef/application/client.rb @@ -501,7 +501,7 @@ class Chef::Application::Client < Chef::Application # we need to sleep again after reconfigure to avoid stampeding when logrotate runs out of cron if signal == RECONFIGURE_SIGNAL reconfigure - interval_sleep(sleep) + interval_sleep(sec) end else sleep(sec) diff --git a/lib/chef/chef_fs/config.rb b/lib/chef/chef_fs/config.rb index 63a1363724..0725426275 100644 --- a/lib/chef/chef_fs/config.rb +++ b/lib/chef/chef_fs/config.rb @@ -66,7 +66,7 @@ class Chef # upgrade/migration of older Chef Servers, so they should be considered # frozen in time. - CHEF_11_OSS_STATIC_OBJECTS = %w{cookbooks cookbook_artifacts data_bags environments roles}.freeze + CHEF_11_OSS_STATIC_OBJECTS = %w{cookbooks data_bags environments roles}.freeze CHEF_11_OSS_DYNAMIC_OBJECTS = %w{clients nodes users}.freeze RBAC_OBJECT_NAMES = %w{acls containers groups }.freeze CHEF_12_OBJECTS = %w{ cookbook_artifacts policies policy_groups client_keys }.freeze diff --git a/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb b/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb index e799e72e36..4b272daabc 100644 --- a/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb +++ b/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb @@ -5,6 +5,8 @@ class Chef module ChefFS module DataHandler class DataBagItemDataHandler < DataHandlerBase + RESERVED_NAMES = /node|role|environment|client/ + def normalize(data_bag_item, entry) # If it's wrapped with raw_data, unwrap it. if data_bag_item["json_class"] == "Chef::DataBagItem" && data_bag_item["raw_data"] @@ -43,6 +45,7 @@ class Chef end # Verify that the JSON hash for this type has a key that matches its name. + # Also check that the data bag name is not a reserved search index name. # # @param object [Object] JSON hash of the object # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying @@ -52,6 +55,8 @@ class Chef base_name = remove_dot_json(entry.name) if object["raw_data"]["id"] != base_name yield("ID in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['raw_data']['id']}')") + elsif entry.parent.name =~ RESERVED_NAMES + yield("Data bag name ('#{entry.parent.name}') must not match #{RESERVED_NAMES.inspect}") end end diff --git a/lib/chef/client.rb b/lib/chef/client.rb index 9f8a34e85e..1211e9425e 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -602,9 +602,12 @@ class Chef # @api private # def run_ohai - filter = Chef::Config[:minimal_ohai] ? %w{fqdn machinename hostname platform platform_version os os_version} : nil + filter = Chef::Config[:minimal_ohai] ? %w{fqdn machinename hostname platform platform_version ohai_time os os_version} : nil ohai.all_plugins(filter) events.ohai_completed(node) + rescue Ohai::Exceptions::CriticalPluginFailure => e + Chef::Log.error("Critical Ohai plugins failed: #{e.message}") + exit(false) end # diff --git a/lib/chef/data_bag.rb b/lib/chef/data_bag.rb index 15531d7304..82eb03fbd7 100644 --- a/lib/chef/data_bag.rb +++ b/lib/chef/data_bag.rb @@ -33,6 +33,7 @@ class Chef include Chef::Mixin::ParamsValidate VALID_NAME = /^[\.\-[:alnum:]_]+$/ + RESERVED_NAMES = /node|role|environment|client/ attr_accessor :chef_server_rest @@ -40,6 +41,9 @@ class Chef unless name =~ VALID_NAME raise Exceptions::InvalidDataBagName, "DataBags must have a name matching #{VALID_NAME.inspect}, you gave #{name.inspect}" end + if name =~ RESERVED_NAMES + raise Exceptions::InvalidDataBagName, "DataBags may not have a name matching #{RESERVED_NAMES.inspect}, you gave #{name.inspect}" + end end # Create a new Chef::DataBag diff --git a/lib/chef/deprecated.rb b/lib/chef/deprecated.rb index 2cf0f3d1bc..183f8e4c24 100644 --- a/lib/chef/deprecated.rb +++ b/lib/chef/deprecated.rb @@ -258,6 +258,16 @@ class Chef end end + class DeployResource < Base + def id + 21 + end + + def target + "deploy_resource.html" + end + end + # id 3694 was deleted class Generic < Base diff --git a/lib/chef/knife/client_delete.rb b/lib/chef/knife/client_delete.rb index 38da5c2a73..82b521c7d1 100644 --- a/lib/chef/knife/client_delete.rb +++ b/lib/chef/knife/client_delete.rb @@ -32,7 +32,7 @@ class Chef :long => "--delete-validators", :description => "Force deletion of client if it's a validator" - banner "knife client delete [CLIENT[,CLIENT]] (options)" + banner "knife client delete [CLIENT [CLIENT]] (options)" def run if @name_args.length == 0 diff --git a/lib/chef/knife/node_delete.rb b/lib/chef/knife/node_delete.rb index b03569cded..52b8d122ca 100644 --- a/lib/chef/knife/node_delete.rb +++ b/lib/chef/knife/node_delete.rb @@ -27,7 +27,7 @@ class Chef require "chef/json_compat" end - banner "knife node delete [NODE[,NODE]] (options)" + banner "knife node delete [NODE [NODE]] (options)" def run if @name_args.length == 0 diff --git a/lib/chef/knife/node_run_list_add.rb b/lib/chef/knife/node_run_list_add.rb index f8d40c8321..fb4ce3bc12 100644 --- a/lib/chef/knife/node_run_list_add.rb +++ b/lib/chef/knife/node_run_list_add.rb @@ -27,7 +27,7 @@ class Chef require "chef/json_compat" end - banner "knife node run_list add [NODE] [ENTRY[,ENTRY]] (options)" + banner "knife node run_list add [NODE] [ENTRY [ENTRY]] (options)" option :after, :short => "-a ITEM", diff --git a/lib/chef/knife/node_run_list_remove.rb b/lib/chef/knife/node_run_list_remove.rb index 3f9cdabfff..df50818c23 100644 --- a/lib/chef/knife/node_run_list_remove.rb +++ b/lib/chef/knife/node_run_list_remove.rb @@ -27,7 +27,7 @@ class Chef require "chef/json_compat" end - banner "knife node run_list remove [NODE] [ENTRY[,ENTRY]] (options)" + banner "knife node run_list remove [NODE] [ENTRY [ENTRY]] (options)" def run node = Chef::Node.load(@name_args[0]) diff --git a/lib/chef/knife/role_env_run_list_add.rb b/lib/chef/knife/role_env_run_list_add.rb index 61aec506a9..4a3bb70641 100644 --- a/lib/chef/knife/role_env_run_list_add.rb +++ b/lib/chef/knife/role_env_run_list_add.rb @@ -27,7 +27,7 @@ class Chef require "chef/json_compat" end - banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY[,ENTRY]] (options)" + banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY [ENTRY]] (options)" option :after, :short => "-a ITEM", diff --git a/lib/chef/knife/role_run_list_add.rb b/lib/chef/knife/role_run_list_add.rb index 6aa92d37ba..7eaaa136bb 100644 --- a/lib/chef/knife/role_run_list_add.rb +++ b/lib/chef/knife/role_run_list_add.rb @@ -27,7 +27,7 @@ class Chef require "chef/json_compat" end - banner "knife role run_list add [ROLE] [ENTRY[,ENTRY]] (options)" + banner "knife role run_list add [ROLE] [ENTRY [ENTRY]] (options)" option :after, :short => "-a ITEM", diff --git a/lib/chef/mixin/user_context.rb b/lib/chef/mixin/user_context.rb index 40a72912a3..526d6b0f3f 100644 --- a/lib/chef/mixin/user_context.rb +++ b/lib/chef/mixin/user_context.rb @@ -23,7 +23,7 @@ class Chef module UserContext def with_user_context(user, password, domain = nil, &block) - if node["platform_family"] != "windows" + unless Chef::Platform.windows? raise Exceptions::UnsupportedPlatform, "User context impersonation is supported only on the Windows platform" end diff --git a/lib/chef/platform/rebooter.rb b/lib/chef/platform/rebooter.rb index 33a6e24be2..430d175869 100644 --- a/lib/chef/platform/rebooter.rb +++ b/lib/chef/platform/rebooter.rb @@ -33,14 +33,18 @@ class Chef def reboot!(node) reboot_info = node.run_context.reboot_info - cmd = if Chef::Platform.windows? + cmd = case + when Chef::Platform.windows? # should this do /f as well? do we then need a minimum delay to let apps quit? # Use explicit path to shutdown.exe, to protect against https://github.com/chef/chef/issues/5594 windows_shutdown_path = "#{ENV['SYSTEMROOT']}/System32/shutdown.exe" "#{windows_shutdown_path} /r /t #{reboot_info[:delay_mins] * 60} /c \"#{reboot_info[:reason]}\"" + when node["os"] == "solaris2" + # SysV-flavored shutdown + "shutdown -i6 -g#{reboot_info[:delay_mins]} -y \"#{reboot_info[:reason]}\" &" else - # probably Linux-only. - "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\"" + # Linux/BSD/Mac/AIX and other systems with BSD-ish shutdown + "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\" &" end msg = "Rebooting server at a recipe's request. Details: #{reboot_info.inspect}" diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb index 654f202ed9..db7a5442ed 100644 --- a/lib/chef/provider/dsc_script.rb +++ b/lib/chef/provider/dsc_script.rb @@ -161,7 +161,11 @@ class Chef if resource.changes_state? # We ignore the last log message because it only contains the time it took, which looks weird cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, "").strip } - "converge DSC resource #{resource.name} by #{cleaned_messages.find_all { |c| c != '' }.join("\n")}" + unless cleaned_messages.empty? + "converge DSC resource #{resource.name} by #{cleaned_messages.find_all { |c| c != '' }.join("\n")}" + else + "converge DSC resource #{resource.name}" + end else # This is needed because a dsc script can have resources that are both converged and not "converge DSC resource #{resource.name} by doing nothing because it is already converged" diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index 4810728524..7116bc9045 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -323,10 +323,38 @@ class Chef # # Note that most likely we need a spaceship operator on versions that subclasses can implement # and we should have `version_compare(v1, v2)` that returns `v1 <=> v2`. + + # This method performs a strict equality check between two strings representing version numbers # + # This function will eventually be deprecated in favour of the below version_equals function. + def target_version_already_installed?(current_version, target_version) - return false unless current_version && target_version - current_version == target_version + version_equals?(current_version, target_version) + end + + # Note that most likely we need a spaceship operator on versions that subclasses can implement + # and we should have `version_compare(v1, v2)` that returns `v1 <=> v2`. + + # This method performs a strict equality check between two strings representing version numbers + # + def version_equals?(v1, v2) + return false unless v1 && v2 + v1 == v2 + end + + # This function compares two version numbers and returns 'spaceship operator' style results, ie: + # if v1 < v2 then return -1 + # if v1 = v2 then return 0 + # if v1 > v2 then return 1 + # if v1 and v2 are not comparable then return nil + # + # By default, this function will use Gem::Version comparison. Subclasses can reimplement this method + # for package-management system specific versions. + def version_compare(v1, v2) + gem_v1 = Gem::Version.new(v1) + gem_v2 = Gem::Version.new(v2) + + gem_v1 <=> gem_v2 end # Check the current_version against the new_resource.version, possibly using fuzzy @@ -439,16 +467,22 @@ class Chef each_package do |package_name, new_version, current_version, candidate_version| case action when :upgrade - if target_version_already_installed?(current_version, new_version) + if version_equals?(current_version, new_version) # this is an odd use case Chef::Log.debug("#{new_resource} #{package_name} #{new_version} is already installed -- you are equality pinning with an :upgrade action, this may be deprecated in the future") target_version_array.push(nil) - elsif target_version_already_installed?(current_version, candidate_version) + elsif version_equals?(current_version, candidate_version) Chef::Log.debug("#{new_resource} #{package_name} #{candidate_version} is already installed") target_version_array.push(nil) elsif candidate_version.nil? Chef::Log.debug("#{new_resource} #{package_name} has no candidate_version to upgrade to") target_version_array.push(nil) + elsif current_version.nil? + Chef::Log.debug("#{new_resource} has no existing installed version. Installing install #{candidate_version}") + target_version_array.push(candidate_version) + elsif version_compare(current_version, candidate_version) == 1 && !new_resource.allow_downgrade + Chef::Log.debug("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{candidate_version}. Skipping...)") + target_version_array.push(nil) else Chef::Log.debug("#{new_resource} #{package_name} is out of date, will upgrade to #{candidate_version}") target_version_array.push(candidate_version) diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb index 3f8c34f50c..3f32f9d380 100644 --- a/lib/chef/provider/package/apt.rb +++ b/lib/chef/provider/package/apt.rb @@ -127,6 +127,22 @@ class Chef private + # compare 2 versions to each other to see which is newer. + # this differs from the standard package method because we + # need to be able to parse debian version strings which contain + # tildes which Gem cannot properly parse + # + # @return [Integer] 1 if v1 > v2. 0 if they're equal. -1 if v1 < v2 + def version_compare(v1, v2) + if !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "gt", v2.to_s).error? + 1 + elsif !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "eq", v2.to_s).error? + 0 + else + -1 + end + end + # Runs command via shell_out with magic environment to disable # interactive prompts. Command is run with default localization rather # than forcing locale to "C", so command output may not be stable. diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb index a1ec4504a0..3536d807ad 100644 --- a/lib/chef/provider/package/chocolatey.rb +++ b/lib/chef/provider/package/chocolatey.rb @@ -141,6 +141,17 @@ EOS private + def version_compare(v1, v2) + if v1 == "latest" || v2 == "latest" + return 0 + end + + gem_v1 = Gem::Version.new(v1) + gem_v2 = Gem::Version.new(v2) + + gem_v1 <=> gem_v2 + end + # Magic to find where chocolatey is installed in the system, and to # return the full path of choco.exe # @@ -226,15 +237,20 @@ EOS # # @return [Hash] name-to-version mapping of available packages def available_packages - @available_packages ||= - begin - cmd = [ "list -r #{package_name_array.join ' '}" ] - cmd.push( "-source #{new_resource.source}" ) if new_resource.source - raw = parse_list_output(*cmd) - raw.keys.each_with_object({}) do |name, available| - available[name] = desired_name_versions[name] || raw[name] + return @available_packages if @available_packages + @available_packages = {} + package_name_array.each do |pkg| + available_versions = + begin + cmd = [ "list -r #{pkg}" ] + cmd.push( "-source #{new_resource.source}" ) if new_resource.source + raw = parse_list_output(*cmd) + raw.keys.each_with_object({}) do |name, available| + available[name] = desired_name_versions[name] || raw[name] + end end - end + @available_packages.merge! available_versions + end @available_packages end diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb index 31279e8312..7843bc74fc 100644 --- a/lib/chef/provider/package/dnf.rb +++ b/lib/chef/provider/package/dnf.rb @@ -35,13 +35,18 @@ class Chef use_multipackage_api use_package_name_for_source - provides :package, platform_family: %w{fedora amazon} do - which("dnf") && shell_out("rpm -q dnf").stdout =~ /^dnf-[1-9]/ - end + # all rhel variants >= 8 will use DNF + provides :package, platform_family: "rhel", platform_version: ">= 8" + + # fedora >= 22 uses DNF + provides :package, platform: "fedora", platform_version: ">= 22" - provides :package, platform_family: %w{rhel}, platform_version: ">= 8" + # amazon will eventually use DNF + provides :package, platform: "amazon" do + which("dnf") + end - provides :dnf_package, os: "linux" + provides :dnf_package # # Most of the magic in this class happens in the python helper script. The ruby side of this @@ -126,6 +131,10 @@ class Chef end end + def version_compare(v1, v2) + python_helper.compare_versions(v1, v2) + end + # @returns Array<Version> def available_version(index) @available_version ||= [] diff --git a/lib/chef/provider/package/dnf/dnf_helper.py b/lib/chef/provider/package/dnf/dnf_helper.py index eb4d238f65..501d6fceee 100644 --- a/lib/chef/provider/package/dnf/dnf_helper.py +++ b/lib/chef/provider/package/dnf/dnf_helper.py @@ -26,6 +26,14 @@ def flushcache(): pass get_sack().load_system_repo(build_cache=True) +def versioncompare(versions): + sack = get_sack() + if (versions[0] is None) or (versions[1] is None): + sys.stdout.write('0\n') + else: + evr_comparison = sack.evr_cmp(versions[0], versions[1]) + sys.stdout.write('{}\n'.format(evr_comparison)) + def query(command): sack = get_sack() @@ -86,5 +94,7 @@ while 1: query(command) elif command['action'] == "flushcache": flushcache() + elif command['action'] == "versioncompare": + versioncompare(command['versions']) 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 index 04f0298861..1801caa1c1 100644 --- a/lib/chef/provider/package/dnf/python_helper.rb +++ b/lib/chef/provider/package/dnf/python_helper.rb @@ -61,6 +61,15 @@ class Chef start if stdin.nil? end + def compare_versions(version1, version2) + with_helper do + json = build_version_query("versioncompare", [version1, version2]) + Chef::Log.debug "sending '#{json}' to python helper" + stdin.syswrite json + "\n" + stdout.sysread(4096).chomp.to_i + end + end + # @returns Array<Version> def query(action, provides, version = nil, arch = nil) with_helper do @@ -109,6 +118,12 @@ class Chef FFI_Yajl::Encoder.encode(hash) end + def build_version_query(action, versions) + hash = { "action" => action } + hash["versions"] = versions + 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 diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb index 89a57affac..cf92e6d3e7 100644 --- a/lib/chef/provider/package/dpkg.rb +++ b/lib/chef/provider/package/dpkg.rb @@ -106,6 +106,22 @@ class Chef private + # compare 2 versions to each other to see which is newer. + # this differs from the standard package method because we + # need to be able to parse debian version strings which contain + # tildes which Gem cannot properly parse + # + # @return [Integer] 1 if v1 > v2. 0 if they're equal. -1 if v1 < v2 + def version_compare(v1, v2) + if !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "gt", v2.to_s).error? + 1 + elsif !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "eq", v2.to_s).error? + 0 + else + -1 + end + end + def read_current_version_of_package(package_name) Chef::Log.debug("#{new_resource} checking install state of #{package_name}") status = shell_out_compact_timeout!("dpkg", "-s", package_name, returns: [0, 1]) diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb index 7ec24f8c24..07617c814e 100644 --- a/lib/chef/provider/package/rpm.rb +++ b/lib/chef/provider/package/rpm.rb @@ -18,6 +18,7 @@ require "chef/provider/package" require "chef/resource/package" require "chef/mixin/get_source_from_package" +require "chef/provider/package/yum/rpm_utils" class Chef class Provider @@ -109,6 +110,10 @@ class Chef private + def version_compare(v1, v2) + Chef::Provider::Package::Yum::RPMVersion.parse(v1) <=> Chef::Provider::Package::Yum::RPMVersion.parse(v2) + end + def uri_scheme?(str) scheme = URI.split(str).first return false unless scheme diff --git a/lib/chef/provider/package/windows.rb b/lib/chef/provider/package/windows.rb index ca9d1e813a..bade7f27a3 100644 --- a/lib/chef/provider/package/windows.rb +++ b/lib/chef/provider/package/windows.rb @@ -165,6 +165,10 @@ class Chef # # @return [Boolean] true if new_version is equal to or included in current_version def target_version_already_installed?(current_version, new_version) + version_equals?(current_version, new_version) + end + + def version_equals?(current_version, new_version) Chef::Log.debug("Checking if #{new_resource} version '#{new_version}' is already installed. #{current_version} is currently installed") if current_version.is_a?(Array) current_version.include?(new_version) @@ -179,6 +183,17 @@ class Chef private + def version_compare(v1, v2) + if v1 == "latest" || v2 == "latest" + return 0 + end + + gem_v1 = Gem::Version.new(v1) + gem_v2 = Gem::Version.new(v2) + + gem_v1 <=> gem_v2 + end + def uninstall_registry_entries @uninstall_registry_entries ||= Chef::Provider::Package::Windows::RegistryUninstallEntry.find_entries(new_resource.package_name) end diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb index d87e421409..7129104224 100644 --- a/lib/chef/provider/package/yum.rb +++ b/lib/chef/provider/package/yum.rb @@ -156,26 +156,6 @@ class Chef yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} versionlock delete #{unlock_str}") end - # Keep upgrades from trying to install an older candidate version. Can happen when a new - # version is installed then removed from a repository, now the older available version - # shows up as a viable install candidate. - # - # Can be done in upgrade_package but an upgraded from->to log message slips out - # - # Hacky - better overall solution? Custom compare in Package provider? - def action_upgrade - # Could be uninstalled or have no candidate - if current_resource.version.nil? || !candidate_version_array.any? - super - elsif candidate_version_array.zip(current_version_array).any? do |c, i| - RPMVersion.parse(c) > RPMVersion.parse(i) - end - super - else - Chef::Log.debug("#{new_resource} is at the latest version - nothing to do") - end - end - private # @@ -190,6 +170,10 @@ class Chef end end + def version_compare(v1, v2) + RPMVersion.parse(v1) <=> RPMVersion.parse(v2) + end + # Enable or disable YumCache extra_repo_control def manage_extra_repo_control if new_resource.options diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb index 41e8433046..77d619d205 100644 --- a/lib/chef/provider/package/zypper.rb +++ b/lib/chef/provider/package/zypper.rb @@ -103,7 +103,7 @@ class Chef end def install_package(name, version) - zypper_package("install", *options, "--auto-agree-with-licenses", name, version) + zypper_package("install", *options, "--auto-agree-with-licenses", allow_downgrade, name, version) end def upgrade_package(name, version) @@ -147,6 +147,10 @@ class Chef def gpg_checks "--no-gpg-checks" unless new_resource.gpg_check end + + def allow_downgrade + "--oldpackage" if new_resource.allow_downgrade + end end end end diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb index 2439f45eda..be695dd83a 100644 --- a/lib/chef/provider/route.rb +++ b/lib/chef/provider/route.rb @@ -186,7 +186,7 @@ class Chef network_file_name = "/etc/sysconfig/network" converge_by("write route default route to #{network_file_name}") do Chef::Log.debug("#{new_resource} writing default route #{new_resource.gateway} to #{network_file_name}") - if ::File.exists?(network_file_name) + if ::File.exist?(network_file_name) network_file = ::Chef::Util::FileEdit.new(network_file_name) network_file.search_file_replace_line /^GATEWAY=/, "GATEWAY=#{new_resource.gateway}" network_file.insert_line_if_no_match /^GATEWAY=/, "GATEWAY=#{new_resource.gateway}" diff --git a/lib/chef/provider/windows_task.rb b/lib/chef/provider/windows_task.rb index b090a3c1d3..588a731767 100644 --- a/lib/chef/provider/windows_task.rb +++ b/lib/chef/provider/windows_task.rb @@ -89,11 +89,17 @@ class Chef basic_validation options = {} options["F"] = "" if new_resource.force || task_need_update? - options["SC"] = schedule + if schedule == :none + options["SC"] = :once + options["ST"] = "00:00" + options["SD"] = convert_user_date_to_system_date "12/12/2012" + else + options["SC"] = schedule + options["ST"] = new_resource.start_time unless new_resource.start_time.nil? + options["SD"] = convert_user_date_to_system_date new_resource.start_day unless new_resource.start_day.nil? + end options["MO"] = new_resource.frequency_modifier if frequency_modifier_allowed options["I"] = new_resource.idle_time unless new_resource.idle_time.nil? - options["SD"] = convert_user_date_to_system_date new_resource.start_day unless new_resource.start_day.nil? - options["ST"] = new_resource.start_time unless new_resource.start_time.nil? options["TR"] = new_resource.command options["RU"] = new_resource.user options["RP"] = new_resource.password if use_password? @@ -277,6 +283,7 @@ class Chef :daily => "Triggers/CalendarTrigger/RandomDelay", :weekly => "Triggers/CalendarTrigger/RandomDelay", :monthly => "Triggers/CalendarTrigger/RandomDelay", + :none => "Triggers", } xml_element_mapping = { @@ -297,6 +304,12 @@ class Chef doc = REXML::Document.new(xml_cmd.stdout) + if new_resource.frequency == :none + doc.root.elements.delete(xml_element_mapping["random_delay"]) + trigger_element = REXML::Element.new(xml_element_mapping["random_delay"]) + doc.root.elements.add(trigger_element) + end + options.each do |option| Chef::Log.debug 'Removing former #{option} if any' doc.root.elements.delete(xml_element_mapping[option]) @@ -410,7 +423,8 @@ class Chef task[:idle_time] = root.elements["Settings/IdleSettings/Duration"].text if root.elements["Settings/IdleSettings/Duration"] && task[:on_idle] - task[:once] = true if !(task[:repetition_interval] || task[:schedule_by_day] || task[:schedule_by_week] || task[:schedule_by_month] || task[:on_logon] || task[:onstart] || task[:on_idle]) + task[:none] = true if root.elements["Triggers/"] && root.elements["Triggers/"].entries.empty? + task[:once] = true if !(task[:repetition_interval] || task[:schedule_by_day] || task[:schedule_by_week] || task[:schedule_by_month] || task[:on_logon] || task[:onstart] || task[:on_idle] || task[:none]) task[:execution_time_limit] = root.elements["Settings/ExecutionTimeLimit"].text if root.elements["Settings/ExecutionTimeLimit"] #by default PT72H task[:random_delay] = root.elements["Triggers/TimeTrigger/RandomDelay"].text if root.elements["Triggers/TimeTrigger/RandomDelay"] task[:random_delay] = root.elements["Triggers/CalendarTrigger/RandomDelay"].text if root.elements["Triggers/CalendarTrigger/RandomDelay"] @@ -481,6 +495,7 @@ class Chef current_resource.frequency(:onstart) if task_hash[:onstart] current_resource.frequency(:on_idle) if task_hash[:on_idle] current_resource.frequency(:once) if task_hash[:once] + current_resource.frequency(:none) if task_hash[:none] end def set_current_idle_time(idle_time) diff --git a/lib/chef/provider/zypper_repository.rb b/lib/chef/provider/zypper_repository.rb index e6fd917d77..31cf8839b2 100644 --- a/lib/chef/provider/zypper_repository.rb +++ b/lib/chef/provider/zypper_repository.rb @@ -18,24 +18,25 @@ require "chef/resource" require "chef/dsl/declare_resource" -require "chef/mixin/which" require "chef/provider/noop" +require "chef/mixin/shell_out" require "shellwords" class Chef class Provider class ZypperRepository < Chef::Provider - - extend Chef::Mixin::Which - - provides :zypper_repository do - which "zypper" - end + provides :zypper_repository, platform_family: "suse" def load_current_resource end action :create do + if new_resource.gpgautoimportkeys + install_gpg_key(new_resource.gpgkey) + else + Chef::Log.debug("'gpgautoimportkeys' property is set to false. Skipping key import.") + end + declare_resource(:template, "/etc/zypp/repos.d/#{escaped_repo_name}.repo") do if template_available?(new_resource.source) source new_resource.source @@ -51,14 +52,14 @@ class Chef end action :delete do - declare_resource(:execute, "zypper removerepo #{escaped_repo_name}") do - only_if "zypper lr #{escaped_repo_name}" + declare_resource(:execute, "zypper --quiet --non-interactive removerepo #{escaped_repo_name}") do + only_if "zypper --quiet lr #{escaped_repo_name}" end end action :refresh do - declare_resource(:execute, "zypper#{' --gpg-auto-import-keys' if new_resource.gpgautoimportkeys} --quiet --no-confirm refresh --force #{escaped_repo_name}") do - only_if "zypper lr #{escaped_repo_name}" + declare_resource(:execute, "zypper --quiet --non-interactive refresh --force #{escaped_repo_name}") do + only_if "zypper --quiet lr #{escaped_repo_name}" end end @@ -66,14 +67,101 @@ class Chef alias_method :action_remove, :action_delete # zypper repos are allowed to have spaces in the names + # @return [String] escaped repo string def escaped_repo_name Shellwords.escape(new_resource.repo_name) end + # return the specified cookbook name or the cookbook containing the + # resource. + # + # @return [String] name of the cookbook + def cookbook_name + new_resource.cookbook || new_resource.cookbook_name + end + + # determine if a template file is available in the current run + # @param [String] path the path to the template file + # + # @return [Boolean] template file exists or doesn't def template_available?(path) - !path.nil? && run_context.has_template_in_cookbook?(new_resource.cookbook_name, path) + !path.nil? && run_context.has_template_in_cookbook?(cookbook_name, path) + end + + # determine if a cookbook file is available in the run + # @param [String] path the path to the template file + # + # @return [Boolean] cookbook file exists or doesn't + def has_cookbook_file?(fn) + run_context.has_cookbook_file_in_cookbook?(cookbook_name, fn) + end + + # Given the provided key URI determine what kind of chef resource we need + # to fetch the key + # @param [String] uri the uri of the gpg key (local path or http URL) + # + # @raise [Chef::Exceptions::FileNotFound] Key isn't remote or found in the current run + # + # @return [Symbol] :remote_file or :cookbook_file + def key_type(uri) + if uri.start_with?("http") + Chef::Log.debug("Will use :remote_file resource to cache the gpg key locally") + :remote_file + elsif has_cookbook_file?(uri) + Chef::Log.debug("Will use :cookbook_file resource to cache the gpg key locally") + :cookbook_file + else + raise Chef::Exceptions::FileNotFound, "Cannot determine location of gpgkey. Must start with 'http' or be a file managed by Chef." + end end + # is the provided key already installed + # @param [String] key_path the path to the key on the local filesystem + # + # @return [boolean] is the key already known by rpm + def key_installed?(key_path) + so = shell_out("rpm -qa gpg-pubkey*") + # expected output & match: http://rubular.com/r/RdF7EcXEtb + status = /gpg-pubkey-#{key_fingerprint(key_path)}/.match(so.stdout) + Chef::Log.debug("GPG key at #{key_path} is known by rpm? #{status ? "true" : "false"}") + status + end + + # extract the gpg key fingerprint from a local file + # @param [String] key_path the path to the key on the local filesystem + # + # @return [String] the fingerprint of the key + def key_fingerprint(key_path) + so = shell_out!("gpg --with-fingerprint #{key_path}") + # expected output and match: http://rubular.com/r/BpfMjxySQM + fingerprint = /pub\s*\S*\/(\S*)/.match(so.stdout)[1].downcase + Chef::Log.debug("GPG fingerprint of key at #{key_path} is #{fingerprint}") + fingerprint + end + + # install the provided gpg key + # @param [String] uri the uri of the local or remote gpg key + def install_gpg_key(uri) + unless uri + Chef::Log.debug("'gpgkey' property not provided or set to nil. Skipping key import.") + return + end + + cached_keyfile = ::File.join(Chef::Config[:file_cache_path], uri.split("/")[-1]) + + declare_resource(key_type(new_resource.gpgkey), cached_keyfile) do + source uri + mode "0644" + sensitive new_resource.sensitive + action :create + end + + declare_resource(:execute, "import gpg key from #{new_resource.gpgkey}") do + command "/bin/rpm --import #{cached_keyfile}" + not_if { key_installed?(cached_keyfile) } + action :run + end + end end end end diff --git a/lib/chef/resource/deploy.rb b/lib/chef/resource/deploy.rb index b8e6a26f97..f74fe86c12 100644 --- a/lib/chef/resource/deploy.rb +++ b/lib/chef/resource/deploy.rb @@ -84,6 +84,12 @@ class Chef @checkout_branch = "deploy" end + # This resource is deprecated. + def after_created + Chef.deprecated(:deploy_resource, "The #{resource_name} resource (#{source_line}) is deprecated and will be removed from Chef core in 14.0 (April 2018). " \ + "A migration cookbook will be available in the future, see the deprecation documentation for more information.") + end + # where the checked out/cloned code goes def destination @destination ||= shared_path + "/#{@repository_cache}" diff --git a/lib/chef/resource/dnf_package.rb b/lib/chef/resource/dnf_package.rb index d92dc12ec7..05ed895e70 100644 --- a/lib/chef/resource/dnf_package.rb +++ b/lib/chef/resource/dnf_package.rb @@ -29,8 +29,15 @@ class Chef allowed_actions :install, :upgrade, :remove, :purge, :reconfig, :lock, :unlock, :flush_cache - provides :package, platform_family: %w{rhel fedora amazon} do - which("dnf") && shell_out("rpm -q dnf").stdout =~ /^dnf-[1-9]/ + # all rhel variants >= 8 will use DNF + provides :package, platform_family: "rhel", platform_version: ">= 8" + + # fedora >= 22 uses DNF + provides :package, platform: "fedora", platform_version: ">= 22" + + # amazon will eventually use DNF + provides :package, platform: "amazon" do + which("dnf") end provides :dnf_package diff --git a/lib/chef/resource/windows_task.rb b/lib/chef/resource/windows_task.rb index f9c0599c49..235bbdfd67 100644 --- a/lib/chef/resource/windows_task.rb +++ b/lib/chef/resource/windows_task.rb @@ -51,7 +51,8 @@ class Chef :once, :on_logon, :onstart, - :on_idle], default: :hourly + :on_idle, + :none], default: :hourly property :start_day, String property :start_time, String property :day, [String, Integer] @@ -81,7 +82,7 @@ class Chef execution_time_limit("PT72H") end - validate_start_time(start_time) if frequency == :once + validate_start_time(start_time, frequency) validate_start_day(start_day, frequency) if start_day validate_user_and_password(user, password) validate_interactive_setting(interactive_enabled, password) @@ -94,7 +95,7 @@ class Chef private def validate_random_delay(random_delay, frequency) - if [:once, :on_logon, :onstart, :on_idle].include? frequency + if [:once, :on_logon, :onstart, :on_idle, :none].include? frequency raise ArgumentError, "`random_delay` property is supported only for frequency :minute, :hourly, :daily, :weekly and :monthly" end @@ -102,13 +103,17 @@ class Chef end def validate_start_day(start_day, frequency) - if [:once, :on_logon, :onstart, :on_idle].include? frequency + if [:once, :on_logon, :onstart, :on_idle, :none].include? frequency raise ArgumentError, "`start_day` property is not supported with frequency: #{frequency}" end end - def validate_start_time(start_time) - raise ArgumentError, "`start_time` needs to be provided with `frequency :once`" unless start_time + def validate_start_time(start_time, frequency) + if frequency == :once + raise ArgumentError, "`start_time` needs to be provided with `frequency :once`" unless start_time + elsif frequency == :none + raise ArgumentError, "`start_time` property is not supported with `frequency :none`" if start_time + end end SYSTEM_USERS = ['NT AUTHORITY\SYSTEM', "SYSTEM", 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE', 'BUILTIN\USERS', "USERS"].freeze @@ -132,7 +137,7 @@ class Chef end def validate_create_frequency_modifier(frequency, frequency_modifier) - # Currently is handled in create action 'frequency_modifier_allowed' line. Does not allow for frequency_modifier for once,onstart,onlogon,onidle + # Currently is handled in create action 'frequency_modifier_allowed' line. Does not allow for frequency_modifier for once,onstart,onlogon,onidle,none # Note that 'OnEvent' is not a supported frequency. unless frequency.nil? || frequency_modifier.nil? case frequency diff --git a/lib/chef/resource/zypper_package.rb b/lib/chef/resource/zypper_package.rb index 6c6e308159..20b1a9f25f 100644 --- a/lib/chef/resource/zypper_package.rb +++ b/lib/chef/resource/zypper_package.rb @@ -25,6 +25,7 @@ class Chef provides :package, platform_family: "suse" property :gpg_check, [ TrueClass, FalseClass ], default: lazy { Chef::Config[:zypper_check_gpg] } + property :allow_downgrade, [ true, false ], default: false end end end diff --git a/lib/chef/resource/zypper_repository.rb b/lib/chef/resource/zypper_repository.rb index 69a96b42cf..88b6fd9336 100644 --- a/lib/chef/resource/zypper_repository.rb +++ b/lib/chef/resource/zypper_repository.rb @@ -39,6 +39,7 @@ class Chef property :mode, default: "0644" property :refresh_cache, [true, false], default: true property :source, String, regex: /.*/ + property :cookbook, String property :gpgautoimportkeys, [true, false], default: true default_action :create diff --git a/lib/chef/util/dsc/lcm_output_parser.rb b/lib/chef/util/dsc/lcm_output_parser.rb index 9473ca8a86..f19f637b6d 100644 --- a/lib/chef/util/dsc/lcm_output_parser.rb +++ b/lib/chef/util/dsc/lcm_output_parser.rb @@ -28,7 +28,7 @@ class Chef # Parses the output from LCM and returns a list of Chef::Util::DSC::ResourceInfo objects # that describe how the resources affected the system # - # Example: + # Example for WhatIfParser: # parse <<-EOF # What if: [Machine]: LCM: [Start Set ] # What if: [Machine]: LCM: [Start Resource ] [[File]FileToNotBeThere] @@ -53,7 +53,62 @@ class Chef # ) # ] # - def self.parse(lcm_output) + # Example for TestDSCParser: + # parse <<-EOF + # InDesiredState : False + # ResourcesInDesiredState : + # ResourcesNotInDesiredState: {[Environment]texteditor} + # ReturnValue : 0 + # PSComputerName : . + # EOF + # + # would return + # + # [ + # Chef::Util::DSC::ResourceInfo.new( + # '{[Environment]texteditor}', + # true, + # [ + # ] + # ) + # ] + # + + def self.parse(lcm_output, test_dsc_configuration) + test_dsc_configuration ? test_dsc_parser(lcm_output) : what_if_parser(lcm_output) + end + + def self.test_dsc_parser(lcm_output) + lcm_output ||= "" + current_resource = Hash.new + + resources = [] + lcm_output.lines.each do |line| + op_action , op_value = line.strip.split(":") + op_action&.strip! + case op_action + when "InDesiredState" + current_resource[:skipped] = op_value.strip == "True" ? true : false + when "ResourcesInDesiredState" + current_resource[:name] = op_value.strip if op_value + when "ResourcesNotInDesiredState" + current_resource[:name] = op_value.strip if op_value + when "ReturnValue" + current_resource[:context] = nil + end + end + if current_resource[:name] + resources.push(current_resource) + end + + if resources.length > 0 + build_resource_info(resources) + else + raise Chef::Exceptions::LCMParser, "Could not parse:\n#{lcm_output}" + end + end + + def self.what_if_parser(lcm_output) lcm_output ||= "" current_resource = Hash.new diff --git a/lib/chef/util/dsc/local_configuration_manager.rb b/lib/chef/util/dsc/local_configuration_manager.rb index 1f154b1c71..07109f7f92 100644 --- a/lib/chef/util/dsc/local_configuration_manager.rb +++ b/lib/chef/util/dsc/local_configuration_manager.rb @@ -29,7 +29,7 @@ class Chef::Util::DSC def test_configuration(configuration_document, shellout_flags) status = run_configuration_cmdlet(configuration_document, false, shellout_flags) - log_what_if_exception(status.stderr) unless status.succeeded? + log_dsc_exception(status.stderr) unless status.succeeded? configuration_update_required?(status.return_value) end @@ -77,7 +77,7 @@ class Chef::Util::DSC ps4_base_command else if ps_version_gte_5? - "#{common_command_prefix} Test-DscConfiguration -path #{@configuration_path}" + "#{common_command_prefix} Test-DscConfiguration -path #{@configuration_path} | format-list" else ps4_base_command + " -whatif; if (! $?) { exit 1 }" end @@ -88,31 +88,31 @@ class Chef::Util::DSC Chef::Platform.supported_powershell_version?(@node, 5) end - def log_what_if_exception(what_if_exception_output) - if whatif_not_supported?(what_if_exception_output) + def log_dsc_exception(dsc_exception_output) + if whatif_not_supported?(dsc_exception_output) # LCM returns an error if any of the resources do not support the opptional What-If Chef::Log.warn("Received error while testing configuration due to resource not supporting 'WhatIf'") - elsif dsc_module_import_failure?(what_if_exception_output) - Chef::Log.warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{what_if_exception_output.gsub(/\s+/, ' ')}") + elsif dsc_module_import_failure?(dsc_exception_output) + Chef::Log.warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{dsc_exception_output.gsub(/\s+/, ' ')}") else - Chef::Log.warn("Received error while testing configuration:\n#{what_if_exception_output.gsub(/\s+/, ' ')}") + Chef::Log.warn("Received error while testing configuration:\n#{dsc_exception_output.gsub(/\s+/, ' ')}") end end - def whatif_not_supported?(what_if_exception_output) - !! (what_if_exception_output.gsub(/[\r\n]+/, "").gsub(/\s+/, " ") =~ /A parameter cannot be found that matches parameter name 'Whatif'/i) + def whatif_not_supported?(dsc_exception_output) + !! (dsc_exception_output.gsub(/[\r\n]+/, "").gsub(/\s+/, " ") =~ /A parameter cannot be found that matches parameter name 'Whatif'/i) end - def dsc_module_import_failure?(what_if_output) - !! (what_if_output =~ /\sCimException/ && - what_if_output =~ /ProviderOperationExecutionFailure/ && - what_if_output =~ /\smodule\s+is\s+installed/) + def dsc_module_import_failure?(command_output) + !! (command_output =~ /\sCimException/ && + command_output =~ /ProviderOperationExecutionFailure/ && + command_output =~ /\smodule\s+is\s+installed/) end - def configuration_update_required?(what_if_output) - Chef::Log.debug("DSC: DSC returned the following '-whatif' output from test operation:\n#{what_if_output}") + def configuration_update_required?(command_output) + Chef::Log.debug("DSC: DSC returned the following '-whatif' output from test operation:\n#{command_output}") begin - Parser.parse(what_if_output) + Parser.parse(command_output, ps_version_gte_5?) rescue Chef::Exceptions::LCMParser => e Chef::Log.warn("Could not parse LCM output: #{e}") [Chef::Util::DSC::ResourceInfo.new("Unknown DSC Resources", true, ["Unknown changes because LCM output was not parsable."])] diff --git a/lib/chef/version.rb b/lib/chef/version.rb index 63fd85c63c..33f8b0cf00 100644 --- a/lib/chef/version.rb +++ b/lib/chef/version.rb @@ -23,7 +23,7 @@ require "chef/version_string" class Chef CHEF_ROOT = File.expand_path("../..", __FILE__) - VERSION = Chef::VersionString.new("13.5.6") + VERSION = Chef::VersionString.new("13.6.7") end # diff --git a/omnibus/.kitchen.yml b/omnibus/.kitchen.yml index a14d3498de..7042684836 100644 --- a/omnibus/.kitchen.yml +++ b/omnibus/.kitchen.yml @@ -73,6 +73,8 @@ platforms: # # KITCHEN_LOCAL_YAML=.kitchen.vmware.yml kitchen converge chefdk-macosx-109 # + + # OSX <% %w( 10.9 10.10 @@ -86,9 +88,15 @@ platforms: - ['../../omnibus', '/Users/vagrant/omnibus'] - ['../../omnibus-software', '/Users/vagrant/omnibus-software'] <% end %> - - name: windows-2012r2-standard + + <% %w( + 10-enterprise + server-2012r2-standard + ).each do |win_version| %> + # Windows 64-bit + - name: windows-<%= win_version %> driver: - box: chef/windows-server-2012r2-standard # private + box: chef/windows-<%= win_version %> # private synced_folders: # We have to mount this repos enclosing folder as the Omnibus build # gets cranky if the mounted Chef source folder is a symlink. This @@ -102,16 +110,14 @@ platforms: build_user_group: Administrators build_user_password: vagrant chef_omnibus_root: /opscode/angrychef + + # Windows 32-bit # By adding an `i386` to the name the Omnibus cookbook's `load-omnibus-toolchain.bat` # will load the 32-bit version of the MinGW toolchain. - - name: windows-2012r2-standard-i386 + - name: windows-<%= win_version %>-i386 driver: - box: chef/windows-server-2012r2-standard # private + box: chef/windows-<%= win_version %> # private synced_folders: - # We have to mount this repos enclosing folder as the Omnibus build - # gets cranky if the mounted ChefDK source folder is a symlink. This - # mounts at `C:\vagrant\code` and the ChefDK source folder is available - # at `C:\vagrant\code\chef-dk` - ['../..', '/vagrant/code'] provisioner: attributes: @@ -120,6 +126,7 @@ platforms: build_user_group: Administrators build_user_password: vagrant chef_omnibus_root: /opscode/angrychef + <% end %> suites: # - name: angrychef diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock index 2bfb0931e2..2365421c75 100644 --- a/omnibus/Gemfile.lock +++ b/omnibus/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/chef/license_scout - revision: 013b1f8b9663f76fd0d1cd0bb95c8fb5b5198f3f + revision: 11f5c3d644be622eb367fe104750dca4f10ce1e5 specs: license_scout (0.1.3) ffi-yajl (~> 2.2) @@ -9,7 +9,7 @@ GIT GIT remote: https://github.com/chef/omnibus - revision: 52393d7cab443b61790f94c62775d9032d283497 + revision: e3807801e61b9012ea2e0677a60c2bf72c0e4972 specs: omnibus (5.6.1) aws-sdk (~> 2) @@ -26,7 +26,7 @@ GIT GIT remote: https://github.com/chef/omnibus-software - revision: 23de2052e79b7a03d2b0a080d2f6e111ce4c760d + revision: 0f8723f83627b40dcf73052ac066baf8f643cce4 specs: omnibus-software (4.0.0) chef-sugar (>= 3.4.0) @@ -37,15 +37,14 @@ GEM specs: addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) - artifactory (2.8.2) awesome_print (1.8.0) - aws-sdk (2.10.54) - aws-sdk-resources (= 2.10.54) - aws-sdk-core (2.10.54) + aws-sdk (2.10.78) + aws-sdk-resources (= 2.10.78) + aws-sdk-core (2.10.78) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.10.54) - aws-sdk-core (= 2.10.54) + aws-sdk-resources (2.10.78) + aws-sdk-core (= 2.10.78) aws-sigv4 (1.0.2) berkshelf (4.3.5) addressable (~> 2.3, >= 2.3.4) @@ -69,7 +68,7 @@ GEM faraday (~> 0.9.1) httpclient (~> 2.7.0) ridley (~> 4.5) - binding_of_caller (0.7.2) + binding_of_caller (0.7.3) debug_inspector (>= 0.0.1) buff-config (1.0.1) buff-extensions (~> 1.0) @@ -86,12 +85,12 @@ GEM celluloid-io (0.16.2) celluloid (>= 0.16.0) nio4r (>= 1.1.0) - chef-config (13.4.24) + chef-config (13.6.0) addressable fuzzyurl mixlib-config (~> 2.0) mixlib-shellout (~> 2.0) - chef-sugar (3.5.0) + chef-sugar (3.6.0) citrus (3.0.2) cleanroom (1.0.0) coderay (1.1.2) @@ -131,8 +130,7 @@ GEM mixlib-authentication (1.4.2) mixlib-cli (1.7.0) mixlib-config (2.2.4) - mixlib-install (2.1.12) - artifactory + mixlib-install (3.8.0) mixlib-shellout mixlib-versioning thor @@ -154,7 +152,7 @@ GEM nori (2.6.0) octokit (4.7.0) sawyer (~> 0.8.0, >= 0.5.3) - ohai (8.24.1) + ohai (8.25.0) chef-config (>= 12.5.0.alpha.1, < 14) ffi (~> 1.9) ffi-yajl (~> 2.2) @@ -174,7 +172,7 @@ GEM zhexdump (>= 0.0.2) plist (3.3.0) progressbar (1.9.0) - pry (0.11.1) + pry (0.11.2) coderay (~> 1.1.0) method_source (~> 0.9.0) pry-byebug (3.5.0) @@ -215,18 +213,21 @@ GEM molinillo (~> 0.4.2) semverse (~> 1.1) systemu (2.6.5) - test-kitchen (1.17.0) - mixlib-install (>= 1.2, < 3.0) + test-kitchen (1.19.0) + mixlib-install (~> 3.6) mixlib-shellout (>= 1.2, < 3.0) net-scp (~> 1.1) net-ssh (>= 2.9, < 5.0) net-ssh-gateway (~> 1.2) safe_yaml (~> 1.0) thor (~> 0.19, < 0.19.2) + winrm (~> 2.0) + winrm-elevated (~> 1.0) + winrm-fs (~> 1.0.2) thor (0.19.1) timers (4.0.4) hitimes - toml-rb (1.0.0) + toml-rb (1.1.0) citrus (~> 3.0, > 3.0) varia_model (0.4.1) buff-extensions (~> 1.0) @@ -242,6 +243,9 @@ GEM logging (>= 1.6.1, < 3.0) nori (~> 2.0) rubyntlm (~> 0.6.0, >= 0.6.1) + winrm-elevated (1.1.0) + winrm (~> 2.0) + winrm-fs (~> 1.0) winrm-fs (1.0.2) erubis (~> 2.7) logging (>= 1.6.1, < 3.0) @@ -269,4 +273,4 @@ DEPENDENCIES winrm-fs (~> 1.0) BUNDLED WITH - 1.15.4 + 1.16.0 diff --git a/omnibus_overrides.rb b/omnibus_overrides.rb index 5e2f1af4d9..a9b0bad56f 100644 --- a/omnibus_overrides.rb +++ b/omnibus_overrides.rb @@ -1,16 +1,16 @@ # THIS IS NOW HAND MANAGED, JUST EDIT THE THING # .travis.yml and appveyor.yml consume this, # try to keep it machine-parsable. -override :rubygems, version: "2.6.13" +override :rubygems, version: "2.6.14" override :bundler, version: "1.15.4" -override "nokogiri", version: "1.8.0" +override "nokogiri", version: "1.8.1" override "libffi", version: "3.2.1" -override "libiconv", version: "1.14" +override "libiconv", version: "1.15" override "liblzma", version: "5.2.3" override "libtool", version: "2.4.2" -override "libxml2", version: "2.9.4" -override "libxslt", version: "1.1.29" -override "libyaml", version: "0.1.6" +override "libxml2", version: "2.9.5" +override "libxslt", version: "1.1.30" +override "libyaml", version: "0.1.7" override "makedepend", version: "1.0.5" override "ncurses", version: "5.9" override "pkg-config-lite", version: "0.28-1" @@ -19,4 +19,4 @@ override "ruby-windows-devkit-bash", version: "3.1.23-4-msys-1.0.18" override "util-macros", version: "1.19.0" override "xproto", version: "7.0.28" override "zlib", version: "1.2.11" -override "openssl", version: "1.0.2j" +override "openssl", version: "1.0.2m" diff --git a/spec/functional/rebooter_spec.rb b/spec/functional/rebooter_spec.rb index a28491cc0b..36961593b0 100644 --- a/spec/functional/rebooter_spec.rb +++ b/spec/functional/rebooter_spec.rb @@ -35,8 +35,9 @@ describe Chef::Platform::Rebooter do resource end + let(:node) { Chef::Node.new } + let(:run_context) do - node = Chef::Node.new events = Chef::EventDispatch::Dispatcher.new Chef::RunContext.new(node, {}, events) end @@ -44,7 +45,8 @@ describe Chef::Platform::Rebooter do let(:expected) do { :windows => "#{ENV['SYSTEMROOT']}/System32/shutdown.exe /r /t 300 /c \"rebooter spec test\"", - :linux => 'shutdown -r +5 "rebooter spec test"', + :linux => 'shutdown -r +5 "rebooter spec test" &', + :solaris => 'shutdown -i6 -g5 -y "rebooter spec test" &', } end @@ -69,8 +71,9 @@ describe Chef::Platform::Rebooter do end shared_context "test a reboot method" do - def test_rebooter_method(method_sym, is_windows, expected_reboot_str) + def test_rebooter_method(method_sym, is_windows, is_solaris, expected_reboot_str) allow(ChefConfig).to receive(:windows?).and_return(is_windows) + node.automatic["os"] = node.automatic["platform"] = node.automatic["platform_family"] = "solaris2" if is_solaris expect(rebooter).to receive(:shell_out!).once.with(expected_reboot_str) expect(rebooter).to receive(:raise).with(Chef::Exceptions::Reboot) expect(rebooter).to receive(method_sym).once.and_call_original @@ -81,24 +84,32 @@ describe Chef::Platform::Rebooter do describe "when using #reboot_if_needed!" do include_context "test a reboot method" - it "should produce the correct string on Windows", :windows_only do - test_rebooter_method(:reboot_if_needed!, true, expected[:windows]) + it "should produce the correct string on Windows" do + test_rebooter_method(:reboot_if_needed!, true, false, expected[:windows]) + end + + it "should produce a SysV-like shutdown on solaris" do + test_rebooter_method(:reboot_if_needed!, false, true, expected[:solaris]) end - it "should produce the correct (Linux-specific) string on non-Windows" do - test_rebooter_method(:reboot_if_needed!, false, expected[:linux]) + it "should produce a BSD-like shutdown by default" do + test_rebooter_method(:reboot_if_needed!, false, false, expected[:linux]) end end describe "when using #reboot!" do include_context "test a reboot method" - it "should produce the correct string on Windows", :windows_only do - test_rebooter_method(:reboot!, true, expected[:windows]) + it "should produce the correct string on Windows" do + test_rebooter_method(:reboot!, true, false, expected[:windows]) + end + + it "should produce a SysV-like shutdown on solaris" do + test_rebooter_method(:reboot!, false, true, expected[:solaris]) end - it "should produce the correct (Linux-specific) string on non-Windows" do - test_rebooter_method(:reboot!, false, expected[:linux]) + it "should produce a BSD-like shutdown by default" do + test_rebooter_method(:reboot!, false, false, expected[:linux]) end end end diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb index e783356c9f..175809b5c0 100644 --- a/spec/functional/resource/user/useradd_spec.rb +++ b/spec/functional/resource/user/useradd_spec.rb @@ -646,10 +646,10 @@ describe Chef::Provider::User::Useradd, metadata do 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. + (Chef::VersionConstraint.new("~> 6.8").include?(OHAI_SYSTEM["platform_version"].to_f) || Chef::VersionConstraint.new("~> 7.3").include?(OHAI_SYSTEM["platform_version"].to_f)) + # RHEL 6.8 and 7.3 ship with a fixed `usermod` command + # Reference: https://access.redhat.com/errata/RHBA-2016:0864 + # Reference: https://access.redhat.com/errata/RHBA-2016:2322 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") diff --git a/spec/functional/resource/windows_task_spec.rb b/spec/functional/resource/windows_task_spec.rb index c2496c702f..6c4b4c4fdc 100644 --- a/spec/functional/resource/windows_task_spec.rb +++ b/spec/functional/resource/windows_task_spec.rb @@ -163,6 +163,31 @@ describe Chef::Resource::WindowsTask, :windows_only do end end + context "frequency :none" do + subject do + new_resource = Chef::Resource::WindowsTask.new(task_name, run_context) + new_resource.command task_name + new_resource.run_level :highest + new_resource.frequency :none + new_resource.random_delay "" + new_resource + end + + it "creates the scheduled task to run on demand only" do + subject.run_action(:create) + task_details = windows_task_provider.send(:load_task_hash, task_name) + + expect(task_details[:TaskName]).to eq("\\chef-client") + expect(task_details[:TaskToRun]).to eq("chef-client") + expect(task_details[:ScheduleType]).to eq("On demand only") + expect(task_details[:StartTime]).to eq("N/A") + expect(task_details[:StartDate]).to eq("N/A") + expect(task_details[:NextRunTime]).to eq("N/A") + expect(task_details[:none]).to eq(true) + expect(task_details[:run_level]).to eq("HighestAvailable") + end + end + context "frequency :weekly" do subject do new_resource = Chef::Resource::WindowsTask.new(task_name, run_context) diff --git a/spec/functional/win32/security_spec.rb b/spec/functional/win32/security_spec.rb index 40ae99bfa4..f3faf24c52 100644 --- a/spec/functional/win32/security_spec.rb +++ b/spec/functional/win32/security_spec.rb @@ -17,6 +17,8 @@ # require "spec_helper" +require "mixlib/shellout" +require "chef/mixin/user_context" if Chef::Platform.windows? require "chef/win32/security" end @@ -26,13 +28,37 @@ describe "Chef::Win32::Security", :windows_only do expect(Chef::ReservedNames::Win32::Security.has_admin_privileges?).to eq(true) end - # We've done some investigation adding a negative test and it turned - # out to be a lot of work since mixlib-shellout doesn't have user - # support for windows. - # - # TODO - Add negative tests once mixlib-shellout has user support - it "has_admin_privileges? returns false when running as non-admin" do - skip "requires user support in mixlib-shellout" + describe "running as non admin user" do + include Chef::Mixin::UserContext + let(:user) { "security_user" } + let(:password) { "Security@123" } + + let(:domain) do + whoami = Mixlib::ShellOut.new("whoami") + whoami.run_command + whoami.error! + whoami.stdout.split("\\")[0] + end + before do + allow_any_instance_of(Chef::Mixin::UserContext).to receive(:node).and_return({ "platform_family" => "windows" }) + allow(Chef::Platform).to receive(:windows_server_2003?).and_return(false) + allow(Chef::ReservedNames::Win32::Security).to receive(:OpenProcessToken).and_return(true) + add_user = Mixlib::ShellOut.new("net user #{user} #{password} /ADD") + add_user.run_command + add_user.error! + end + + after do + delete_user = Mixlib::ShellOut.new("net user #{user} /delete") + delete_user.run_command + delete_user.error! + end + it "has_admin_privileges? returns false" do + has_admin_privileges = with_user_context(user, password, domain) do + Chef::ReservedNames::Win32::Security.has_admin_privileges? + end + expect(has_admin_privileges).to eq(false) + end end describe "get_file_security" do diff --git a/spec/support/shared/functional/execute_resource.rb b/spec/support/shared/functional/execute_resource.rb index 4f7cea1cd1..1a14bb38c3 100644 --- a/spec/support/shared/functional/execute_resource.rb +++ b/spec/support/shared/functional/execute_resource.rb @@ -63,7 +63,7 @@ shared_context "a command that can be executed as an alternate user" do after do File.delete(script_output_path) if File.exists?(script_output_path) - Dir.rmdir(script_output_dir) if Dir.exists?(script_output_dir) + Dir.rmdir(script_output_dir) if Dir.exist?(script_output_dir) end end diff --git a/spec/unit/chef_fs/data_handler/data_bag_item_data_handler.rb b/spec/unit/chef_fs/data_handler/data_bag_item_data_handler.rb new file mode 100644 index 0000000000..fea7a2d54d --- /dev/null +++ b/spec/unit/chef_fs/data_handler/data_bag_item_data_handler.rb @@ -0,0 +1,79 @@ +# +# Author:: Sandra Tiffin (<sandi.tiffin@gmail.com>) +# Copyright:: Copyright 2014-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 "lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb" + +class TestDataBag < Mash + attr_accessor :name + + def initialize(bag_name) + @name = bag_name + end +end + +class TestDataBagItem < Mash + attr_accessor :name, :parent + + def path_for_printing + "/some/path" + end + + def initialize(bag_name, item_name) + @name = "#{item_name}.json" + @parent = TestDataBag.new(bag_name) + end +end + +describe Chef::ChefFS::DataHandler::DataBagItemDataHandler do + let(:handler) { described_class.new } + + describe "#verify_integrity" do + context "json id does not match data bag item name" do + let(:entry) { TestDataBagItem.new("luggage", "bag") } + let(:object) do + { "raw_data" => { "id" => "duffel" } } + end + it "rejects the data bag item name" do + expect { |b| handler.verify_integrity(object, entry, &b) }.to yield_with_args + end + end + + context "using a reserved word for the data bag name" do + %w{node role environment client}.each do |reserved_word| + let(:entry) { TestDataBagItem.new(reserved_word, "bag") } + let(:object) do + { "raw_data" => { "id" => "bag" } } + end + it "rejects the data bag name '#{reserved_word}'" do + expect { |b| handler.verify_integrity(object, entry, &b) }.to yield_with_args + end + end + end + + context "valid data" do + let(:entry) { TestDataBagItem.new("luggage", "bag") } + let(:object) do + { "raw_data" => { "id" => "bag" } } + end + it "validates the data bag item" do + expect(handler.verify_integrity(object, entry)).to be_nil + end + end + end +end diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb index d348c24385..2aff7b2a71 100644 --- a/spec/unit/client_spec.rb +++ b/spec/unit/client_spec.rb @@ -38,12 +38,23 @@ describe Chef::Client do end it "runs ohai with only the minimum required plugins" do - expected_filter = %w{fqdn machinename hostname platform platform_version os os_version} + expected_filter = %w{fqdn machinename hostname platform platform_version ohai_time os os_version} expect(ohai_system).to receive(:all_plugins).with(expected_filter) client.run_ohai end end + context "when Ohai tells us to fail" do + it "fails" do + ohai_system = Ohai::System.new + module Ohai::Exceptions + class CriticalPluginFailure < Error; end + end + expect(ohai_system).to receive(:all_plugins) { raise Ohai::Exceptions::CriticalPluginFailure } + expect { client.run_ohai }.to raise_error(SystemExit) + end + end + describe "authentication protocol selection" do context "when FIPS is disabled" do before do diff --git a/spec/unit/knife/data_bag_create_spec.rb b/spec/unit/knife/data_bag_create_spec.rb index b7d185a58c..1f99fe74fe 100644 --- a/spec/unit/knife/data_bag_create_spec.rb +++ b/spec/unit/knife/data_bag_create_spec.rb @@ -72,6 +72,14 @@ describe Chef::Knife::DataBagCreate do expect { knife.run }.to exit_with_code(1) end + it "won't create a data bag with a reserved name for search" do + %w{node role client environment}.each do |name| + knife.name_args = [name] + expect(Chef::DataBag).to receive(:validate_name!).with(knife.name_args[0]).and_raise(Chef::Exceptions::InvalidDataBagName) + expect { knife.run }.to exit_with_code(1) + end + end + context "when given one argument" do before do knife.name_args = [bag_name] diff --git a/spec/unit/mixin/user_context_spec.rb b/spec/unit/mixin/user_context_spec.rb index f2119b6dbc..3dadf6a2c3 100644 --- a/spec/unit/mixin/user_context_spec.rb +++ b/spec/unit/mixin/user_context_spec.rb @@ -41,7 +41,6 @@ describe "a class that mixes in user_context" do before do allow(::Chef::Platform).to receive(:windows?).and_return(true) allow(::Chef::Util::Windows::LogonSession).to receive(:new).and_return(logon_session) - allow(instance_with_user_context).to receive(:node).and_return({ "platform_family" => "windows" }) end let(:logon_session) { instance_double("::Chef::Util::Windows::LogonSession", :set_user_context => nil, :open => nil, :close => nil) } @@ -99,7 +98,7 @@ describe "a class that mixes in user_context" do context "when not running on Windows" do before do - allow(instance_with_user_context).to receive(:node).and_return({ "platform_family" => "ubuntu" }) + allow(::Chef::Platform).to receive(:windows?).and_return(false) end it "raises a ::Chef::Exceptions::UnsupportedPlatform exception" do diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index 46ae7fcadc..ff14edcffd 100644 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -475,6 +475,40 @@ mpg123 1.12.1-0ubuntu1 end end + describe "#action_install" do + it "should run dpkg to compare versions if an existing version is installed" do + allow(@provider).to receive(:get_current_versions).and_return("1.4.0") + allow(@new_resource).to receive(:allow_downgrade).and_return(false) + expect(@provider).to receive(:shell_out_compact_timeout).with( + "dpkg", "--compare-versions", "1.4.0", "gt", "0.8.12-7" + ).and_return(double(error?: false)) + @provider.run_action(:upgrade) + end + + it "should install the package if the installed version is older" do + allow(@provider).to receive(:get_current_versions).and_return("0.4.0") + allow(@new_resource).to receive(:allow_downgrade).and_return(false) + expect(@provider).to receive(:version_compare).and_return(-1) + expect(@provider).to receive(:shell_out!).with( + "apt-get", "-q", "-y", "install", "irssi=0.8.12-7", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, + :timeout => @timeout + ) + @provider.run_action(:upgrade) + end + + it "should not compare versions if an existing version is not installed" do + allow(@provider).to receive(:get_current_versions).and_return(nil) + allow(@new_resource).to receive(:allow_downgrade).and_return(false) + expect(@provider).not_to receive(:version_compare) + expect(@provider).to receive(:shell_out!).with( + "apt-get", "-q", "-y", "install", "irssi=0.8.12-7", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, + :timeout => @timeout + ) + @provider.run_action(:upgrade) + end + end end end end diff --git a/spec/unit/provider/package/chocolatey_spec.rb b/spec/unit/provider/package/chocolatey_spec.rb index 68b121960c..afc068041d 100644 --- a/spec/unit/provider/package/chocolatey_spec.rb +++ b/spec/unit/provider/package/chocolatey_spec.rb @@ -59,7 +59,9 @@ 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}", { :returns => [0], timeout: timeout }).and_return(remote_list_obj) + package_names.each do |pkg| + allow(provider).to receive(:shell_out!).with("#{choco_exe} list -r #{pkg}#{args}", { :returns => [0], timeout: timeout }).and_return(remote_list_obj) + end end describe "#initialize" do diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb index 856f8d460c..ac2b511ca9 100644 --- a/spec/unit/provider/package/rubygems_spec.rb +++ b/spec/unit/provider/package/rubygems_spec.rb @@ -383,6 +383,11 @@ describe Chef::Provider::Package::Rubygems do provider.load_current_resource expect(provider.target_version_already_installed?(provider.current_resource.version, new_resource.version)).to be_falsey end + + it "version_equals? should return false so that we can search for candidates" do + provider.load_current_resource + expect(provider.version_equals?(provider.current_resource.version, new_resource.version)).to be_falsey + end end describe "when new_resource version is an rspec version" do diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb index b20a548c73..598fedc9fa 100644 --- a/spec/unit/provider/package/zypper_spec.rb +++ b/spec/unit/provider/package/zypper_spec.rb @@ -140,6 +140,14 @@ describe Chef::Provider::Package::Zypper do provider.install_package(["emacs"], ["1.0"]) end + it "setting the property should allow downgrade" do + new_resource.allow_downgrade true + shell_out_expectation!( + "zypper", "--non-interactive", "install", "--auto-agree-with-licenses", "--oldpackage", "emacs=1.0" + ) + provider.install_package(["emacs"], ["1.0"]) + end + it "should add user provided options to the command" do new_resource.options "--user-provided" shell_out_expectation!( diff --git a/spec/unit/provider/remote_file/network_file_spec.rb b/spec/unit/provider/remote_file/network_file_spec.rb index 621d2769a4..ecb326fc64 100644 --- a/spec/unit/provider/remote_file/network_file_spec.rb +++ b/spec/unit/provider/remote_file/network_file_spec.rb @@ -33,7 +33,7 @@ describe Chef::Provider::RemoteFile::NetworkFile do let(:source_file) { double("::File", :read => nil) } before do - allow(fetcher).to receive(:node).and_return({ "platform_family" => "windows" }) + allow(Chef::Platform).to receive(:windows?).and_return(true) end it "stages the local file to a temporary file" do diff --git a/spec/unit/provider/route_spec.rb b/spec/unit/provider/route_spec.rb index 5e655bda0c..ea6ddffb81 100644 --- a/spec/unit/provider/route_spec.rb +++ b/spec/unit/provider/route_spec.rb @@ -236,9 +236,11 @@ describe Chef::Provider::Route do @node.automatic_attrs[:platform] = platform route_file = StringIO.new + allow(File).to receive(:exist?).with("/etc/sysconfig/network").and_return(false) expect(File).to receive(:new).with("/etc/sysconfig/network", "w").and_return(route_file) @run_context.resource_collection << @default_resource @default_provider.generate_config + expect(route_file.string).to match(/GATEWAY=10\.0\.0\.9/) end end diff --git a/spec/unit/provider/windows_task_spec.rb b/spec/unit/provider/windows_task_spec.rb index b18d842bfa..55a1e77e4e 100644 --- a/spec/unit/provider/windows_task_spec.rb +++ b/spec/unit/provider/windows_task_spec.rb @@ -143,6 +143,17 @@ describe Chef::Provider::WindowsTask do provider.run_action(:create) expect(new_resource).to be_updated_by_last_action end + + it "updates the task XML if frequency is set as `:none`" do + new_resource.frequency :none + new_resource.random_delay "" + allow(provider).to receive(:task_need_update?).and_return(true) + allow(provider).to receive(:basic_validation).and_return(true) + allow(provider).to receive(:run_schtasks).and_return("CREATE", { "F" => "", "SC" => :once, "ST" => "00:00", "SD" => "12/12/2012", "TR" => nil, "RU" => "SYSTEM" }) + expect(provider).to receive(:update_task_xml) + provider.run_action(:create) + expect(new_resource).to be_updated_by_last_action + end end end @@ -507,6 +518,18 @@ describe Chef::Provider::WindowsTask do expect(provider).to receive(:run_schtasks).twice output = provider.send(:update_task_xml, ["random_delay"]) end + + it "updates the task XML if frequency is set as `:none`" do + new_resource.frequency :none + new_resource.random_delay "" + shell_out_obj = double("xml", :exitstatus => 0, :stdout => task_xml) + allow(provider).to receive(:powershell_out).and_return(shell_out_obj) + expect(::File).to receive(:delete) + expect(::File).to receive(:join) + expect(::File).to receive(:open) + expect(provider).to receive(:run_schtasks).twice + output = provider.send(:update_task_xml, ["random_delay"]) + end end describe "#load_task_hash" do @@ -541,5 +564,10 @@ describe Chef::Provider::WindowsTask do new_resource.frequency :once expect(provider.send(:frequency_modifier_allowed)).to be(false) end + + it "returns false for frequency :none" do + new_resource.frequency :none + expect(provider.send(:frequency_modifier_allowed)).to be(false) + end end end diff --git a/spec/unit/provider/zypper_repository_spec.rb b/spec/unit/provider/zypper_repository_spec.rb new file mode 100644 index 0000000000..a366a33e86 --- /dev/null +++ b/spec/unit/provider/zypper_repository_spec.rb @@ -0,0 +1,124 @@ +# +# Author:: Tim Smith (<tsmith@chef.io>) +# 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" + +# Output of the command: +# => rpm -qa gpg-pubkey* +RPM_KEYS = <<-EOF +gpg-pubkey-307e3d54-4be01a65 +gpg-pubkey-3dbdc284-53674dd4 +EOF + +# Output of the command: +# => gpg --with-fingerprint [FILE] +GPG_FINGER = <<-EOF +pub 2048R/3DBDC284 2011-08-19 [expires: 2024-06-14] + Key fingerprint = 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62 +uid nginx signing key <signing-key@nginx.com> +EOF + +describe Chef::Provider::ZypperRepository do + let(:new_resource) { Chef::Resource::ZypperRepository.new("Nginx Repository") } + let(:provider) do + node = Chef::Node.new + events = Chef::EventDispatch::Dispatcher.new + run_context = Chef::RunContext.new(node, {}, events) + Chef::Provider::ZypperRepository.new(new_resource, run_context) + end + + let(:rpm_key_finger) do + double("shell_out_with_systems_locale", stdout: RPM_KEYS, exitstatus: 0, error?: false) + end + + let(:gpg_finger) do + double("shell_out_with_systems_locale", stdout: GPG_FINGER, exitstatus: 0, error?: false) + end + + it "responds to load_current_resource" do + expect(provider).to respond_to(:load_current_resource) + end + + describe "#action_create" do + it "skips key import if gpgautoimportkeys is false" do + new_resource.gpgautoimportkeys(false) + expect(provider).to receive(:declare_resource) + expect(Chef::Log).to receive(:debug) + provider.run_action(:create) + end + end + + describe "#escaped_repo_name" do + it "returns an escaped repo name" do + expect(provider.escaped_repo_name).to eq('Nginx\\ Repository') + end + end + + describe "#cookbook_name" do + it "returns 'test' when the cookbook property is set" do + new_resource.cookbook("test") + expect(provider.cookbook_name).to eq("test") + end + end + + describe "#key_type" do + it "returns :remote_file with an http URL" do + expect(provider.key_type("https://www.chef.io/key")).to eq(:remote_file) + end + + it "returns :cookbook_file with a chef managed file" do + expect(provider).to receive(:has_cookbook_file?).and_return(true) + expect(provider.key_type("/foo/nginx.key")).to eq(:cookbook_file) + end + + it "throws exception if an unknown file specified" do + expect(provider).to receive(:has_cookbook_file?).and_return(false) + expect { provider.key_type("/foo/nginx.key") }.to raise_error(Chef::Exceptions::FileNotFound) + end + end + + describe "#key_installed?" do + before do + expect(provider).to receive(:shell_out).with("rpm -qa gpg-pubkey*").and_return(rpm_key_finger) + end + + it "returns true if the key is installed" do + expect(provider).to receive(:key_fingerprint).and_return("3dbdc284") + expect(provider.key_installed?("/foo/nginx.key")).to be_truthy + end + + it "returns false if the key is not installed" do + expect(provider).to receive(:key_fingerprint).and_return("BOGUS") + expect(provider.key_installed?("/foo/nginx.key")).to be_falsey + end + end + + describe "#key_fingerprint" do + it "returns the key's fingerprint" do + expect(provider).to receive(:shell_out!).with("gpg --with-fingerprint /foo/nginx.key").and_return(gpg_finger) + expect(provider.key_fingerprint("/foo/nginx.key")).to eq("3dbdc284") + end + end + + describe "#install_gpg_key" do + it "skips installing the key if a nil value for key is passed" do + expect(Chef::Log).to receive(:debug) + provider.install_gpg_key(nil) + end + end +end diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb index 1902fb5375..d1aaa6a8ea 100644 --- a/spec/unit/provider_resolver_spec.rb +++ b/spec/unit/provider_resolver_spec.rb @@ -708,18 +708,21 @@ describe Chef::ProviderResolver do "rhel" => { # service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ], - package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], + package: [ Chef::Resource::DnfPackage, Chef::Provider::Package::Dnf ], ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ], %w{amazon xcp xenserver ibm_powerkvm cloudlinux parallels} => { "3.1.4" => { + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, %w{redhat centos scientific oracle} => { "7.0" => { + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], }, "6.0" => { + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, diff --git a/spec/unit/resource/windows_task_spec.rb b/spec/unit/resource/windows_task_spec.rb index 2b3ee16024..cf4651cf52 100644 --- a/spec/unit/resource/windows_task_spec.rb +++ b/spec/unit/resource/windows_task_spec.rb @@ -102,8 +102,14 @@ describe Chef::Resource::WindowsTask do end context "#validate_start_time" do - it "raises error if start_time is nil" do - expect { resource.send(:validate_start_time, nil) }.to raise_error(Chef::Exceptions::ArgumentError, "`start_time` needs to be provided with `frequency :once`") + it "raises error if start_time is nil when frequency `:once`" do + resource.frequency :once + expect { resource.send(:validate_start_time, nil, :once) }.to raise_error(Chef::Exceptions::ArgumentError, "`start_time` needs to be provided with `frequency :once`") + end + + it "raises error if start_time is given when frequency `:none`" do + resource.frequency :none + expect { resource.send(:validate_start_time, "12.00", :none) }.to raise_error(Chef::Exceptions::ArgumentError, "`start_time` property is not supported with `frequency :none`") end end diff --git a/spec/unit/resource/zypper_repository_spec.rb b/spec/unit/resource/zypper_repository_spec.rb index 16951d071c..de08b183a5 100644 --- a/spec/unit/resource/zypper_repository_spec.rb +++ b/spec/unit/resource/zypper_repository_spec.rb @@ -46,20 +46,22 @@ describe Chef::Resource::ZypperRepository do expect { resource.action :delete }.to raise_error(ArgumentError) end - it "should resolve to a Noop class when zypper is not found" do - expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(false) + it "resolves to a Noop class when on non-linux OS" do + node.automatic[:os] = "windows" + node.automatic[:platform_family] = "windows" expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop) end - it "should resolve to a ZypperRepository class when zypper is found" do - expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(true) - expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::ZypperRepository) + it "resolves to a Noop class when on non-suse linux" do + node.automatic[:os] = "linux" + node.automatic[:platform_family] = "debian" + expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop) end - end - context "on windows", :windows_only do - it "should resolve to a NoOp provider" do - expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop) + it "resolves to a ZypperRepository class when on a suse platform_family" do + node.automatic[:os] = "linux" + node.automatic[:platform_family] = "suse" + expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::ZypperRepository) end end end diff --git a/spec/unit/util/dsc/lcm_output_parser_spec.rb b/spec/unit/util/dsc/lcm_output_parser_spec.rb index d59497de6f..65eaafe19c 100644 --- a/spec/unit/util/dsc/lcm_output_parser_spec.rb +++ b/spec/unit/util/dsc/lcm_output_parser_spec.rb @@ -19,20 +19,33 @@ require "chef/util/dsc/lcm_output_parser" describe Chef::Util::DSC::LocalConfigurationManager::Parser do - context "empty input parameter" do + context "empty input parameter for WhatIfParser" do it "raises an exception when there are no valid lines" do str = <<-EOF EOF - expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) }.to raise_error(Chef::Exceptions::LCMParser) + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) }.to raise_error(Chef::Exceptions::LCMParser) end it "raises an exception for a nil input" do - expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(nil) }.to raise_error(Chef::Exceptions::LCMParser) + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(nil, false) }.to raise_error(Chef::Exceptions::LCMParser) end end - context "correctly formatted output from lcm" do + context "empty input parameter for TestDSCParser" do + it "raises an exception when there are no valid lines" do + str = <<-EOF + + EOF + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) }.to raise_error(Chef::Exceptions::LCMParser) + end + + it "raises an exception for a nil input" do + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(nil, true) }.to raise_error(Chef::Exceptions::LCMParser) + end + end + + context "correctly formatted output from lcm for WhatIfParser" do it "returns a single resource when only 1 logged with the correct name" do str = <<EOF logtype: [machinename]: LCM: [ Start Set ] @@ -40,7 +53,7 @@ logtype: [machinename]: LCM: [ Start Resource ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources.length).to eq(1) expect(resources[0].name).to eq("[name]") end @@ -54,7 +67,7 @@ logtype: [machinename]: LCM: [ End Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_truthy end @@ -68,11 +81,11 @@ logtype: [machinename]: LCM: [ End Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].change_log).to match_array(["[name]", "[message]", "[name]"]) end - it "should return false for changes_state?" do + it "returns false for changes_state?" do str = <<EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -80,11 +93,11 @@ logtype: [machinename]: LCM: [ Skip Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_falsey end - it "should return an empty array for change_log if changes_state? is false" do + it "returns an empty array for change_log if changes_state? is false" do str = <<EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -92,13 +105,64 @@ logtype: [machinename]: LCM: [ Skip Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].change_log).to be_empty end end - context "Incorrectly formatted output from LCM" do - it "should allow missing a [End Resource] when its the last one and still find all the resource" do + context "correctly formatted output from lcm for TestDSCParser" do + it "returns a single resource when only 1 logged with the correct name" do + str = <<EOF +InDesiredState : False +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name] +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources.length).to eq(1) + expect(resources[0].name).to eq("[name]") + end + + it "identifies when a resource changes the state of the system" do + str = <<EOF +InDesiredState : False +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name] +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].changes_state?).to be_truthy + end + + it "returns false for changes_state?" do + str = <<EOF +InDesiredState : True +ResourcesInDesiredState : [name] +ResourcesNotInDesiredState: +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].changes_state?).to be_falsey + end + + it "returns an empty array for change_log if changes_state? is false" do + str = <<EOF +InDesiredState : True +ResourcesInDesiredState : [name] +ResourcesNotInDesiredState: +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].change_log).to be_empty + end + end + + context "Incorrectly formatted output from LCM for WhatIfParser" do + it "allows missing [End Resource] when its the last one and still find all the resource" do str = <<-EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -114,12 +178,12 @@ logtype: [machinename]: LCM: [ End Set ] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_falsey expect(resources[1].changes_state?).to be_truthy end - it "should allow missing a [End Resource] when its the first one and still find all the resource" do + it "allow missing [End Resource] when its the first one and still find all the resource" do str = <<-EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -135,12 +199,12 @@ logtype: [machinename]: LCM: [ End Resource ] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_falsey expect(resources[1].changes_state?).to be_truthy end - it "should allow missing set and end resource and assume an unconverged resource in this case" do + it "allows missing set and end resource and assume an unconverged resource in this case" do str = <<-EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -154,11 +218,31 @@ logtype: [machinename]: LCM: [ End Set ] logtype: [machinename]: LCM: [ End Resource ] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_truthy expect(resources[0].name).to eql("[name]") expect(resources[1].changes_state?).to be_truthy expect(resources[1].name).to eql("[name2]") end end + + context "Incorrectly formatted output from LCM for TestDSCParser" do + it "allows missing [End Resource] when its the last one and still find all the resource" do + str = <<EOF +InDesiredState : True +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name] +ReturnValue : 0 +PSComputerName : . +InDesiredState : True +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name2] +ReturnValue : 0 +PSComputerName : . +EOF + + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].changes_state?).to be_falsey + end + end end diff --git a/spec/unit/util/dsc/local_configuration_manager_spec.rb b/spec/unit/util/dsc/local_configuration_manager_spec.rb index c87b446286..4c33fc8616 100644 --- a/spec/unit/util/dsc/local_configuration_manager_spec.rb +++ b/spec/unit/util/dsc/local_configuration_manager_spec.rb @@ -57,6 +57,7 @@ EOH context "when interacting with the LCM using a PowerShell cmdlet" do before(:each) do allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status) + allow(lcm).to receive(:ps_version_gte_5?).and_return(false) end context "that returns successfully" do let(:lcm_standard_output) { normal_lcm_output } @@ -103,7 +104,7 @@ EOH let(:common_command_prefix) { "$ProgressPreference = 'SilentlyContinue';" } let(:ps4_base_command) { "#{common_command_prefix} Start-DscConfiguration -path tmp -wait -erroraction 'stop' -force" } let(:lcm_command_ps4) { ps4_base_command + " -whatif; if (! $?) { exit 1 }" } - let(:lcm_command_ps5) { "#{common_command_prefix} Test-DscConfiguration -path tmp" } + let(:lcm_command_ps5) { "#{common_command_prefix} Test-DscConfiguration -path tmp | format-list" } let(:lcm_standard_output) { normal_lcm_output } let(:lcm_standard_error) { nil } let(:lcm_cmdlet_success) { true } |