diff options
86 files changed, 958 insertions, 1173 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b4eac50d28..8029e13382 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,7 @@ # Order is important. The last matching pattern has the most precedence. -* @chef/client-maintainers -.expeditor/** @chef/jex-team -README.md @chef/docs-team -RELEASE_NOTES.md @chef/docs-team +* @chef/client-maintainers +.expeditor/** @chef/jex-team +README.md @chef/docs-team +RELEASE_NOTES.md @chef/docs-team +.github/ISSUE_TEMPLATE/** @chef/docs-team diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md index c6f0984993..7d9433c10f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md @@ -1,4 +1,10 @@ -<!--- +--- +name: 🐛 Bug Report +about: If something isn't working as expected 🤔. + +--- + +<!--- !!!!!! NOTE: CHEF CLIENT BUGS ONLY !!!!!! This issue tracker is for the code contained within this repo -- `chef-client`, base `knife` functionality (not diff --git a/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md b/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..0e06843554 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +--- +name: 🚀 Enhancement Request +about: I have a suggestion (and may want to implement it 🙂)! + +--- + +### Describe the Enhancement: +<!--- What you are trying to achieve that you can't? --> + +### Describe the Need: +<!--- What kind of user do you believe would utilize this enhancement, and how many users might want this functionality --> + +### Current Alternative +<!--- Is there a current alternative that you can utilize to workaround the lack of this enhancement --> + +### Can We Help You Implement This?: +<!--- The best way to ensure your enhancement is built is to help implement the enhancement yourself. If you're interested in helping out we'd love to give you a hand to make this possible. Let us know if there's something you need. --> diff --git a/.github/ISSUE_TEMPLATE/RESOURCE_REQUEST.md b/.github/ISSUE_TEMPLATE/RESOURCE_REQUEST.md new file mode 100644 index 0000000000..c94713f0e4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/RESOURCE_REQUEST.md @@ -0,0 +1,26 @@ +--- +name: 💪 Resource Request +about: I have a suggestion for a new resource in Chef (and may want to implement it 🙌)! + +--- + +### Core Chef Resource Checklist + +Before suggesting a resource for inclusion please make sure your suggestion meets these criteria for resources built into Chef: + - [ ] Automates an operating system component that ships by default on systems such as authentication, raid, disk partitions, firewalls, containers, or virtualization systems. + - [ ] Does not attempt automate 3rd party applications such as database, web, or application servers, which are best suited for cookbooks due to their fast moving nature. + +### Describe the resource: +<!--- Tell us about the resource --> + +### Why should this be included out of the box?: +<!--- Why do you believe this is best suited to be included in the chef-client vs. a cookbook? --> + +### What operating systems would it run on? +<!--- Is this a general purpose resource that would run on every operating systems or is it specific to an OS such as Linux, macOS, or Windows? --> + +### Current cookbook implementation: +<!--- Is there currently a cookbook that ships with this resource? If so please let us know. We'll need full permission from the authors and a compatible license in order to move a resource from a cookbook. --> + +### Can We Help You Implement This?: +<!--- The best way to move a resource into Chef is to help move it yourself. If you're interested in helping out we'd love to give you a hand to make this possible. Let us know if there's something you need. --> diff --git a/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md b/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md new file mode 100644 index 0000000000..f506318876 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md @@ -0,0 +1,13 @@ +--- +name: 🤗 Support Question +about: If you have a question 💬, please check out our Slack! + +--- + +We use GitHub issues to track bugs and feature requests. If you need help please post to our Mailing List or join the Chef Community Slack. + + * Chef Community Slack at http://community-slack.chef.io/. + * Chef Mailing List https://discourse.chef.io/ + + + Support issues opened here will be closed and redirected to Slack or Discourse. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e196c2b74..c4fafbfd1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,23 @@ <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ --> -<!-- latest_release 15.0.32 --> -## [v15.0.32](https://github.com/chef/chef/tree/v15.0.32) (2018-11-02) +<!-- latest_release 15.0.40 --> +## [v15.0.40](https://github.com/chef/chef/tree/v15.0.40) (2018-11-05) #### Merged Pull Requests -- powershell_package doc update [#7857](https://github.com/chef/chef/pull/7857) ([Happycoil](https://github.com/Happycoil)) +- Make knife command banners consistent [#7869](https://github.com/chef/chef/pull/7869) ([tas50](https://github.com/tas50)) <!-- latest_release --> <!-- release_rollup --> ### Changes since latest stable release #### Merged Pull Requests +- Make knife command banners consistent [#7869](https://github.com/chef/chef/pull/7869) ([tas50](https://github.com/tas50)) <!-- 15.0.40 --> +- Add windows_firewall_rule [#7842](https://github.com/chef/chef/pull/7842) ([Happycoil](https://github.com/Happycoil)) <!-- 15.0.39 --> +- Improve resource descriptions for resource documentation automation [#7808](https://github.com/chef/chef/pull/7808) ([tas50](https://github.com/tas50)) <!-- 15.0.38 --> +- Remove the remaining OSC 11 knife user commands [#7868](https://github.com/chef/chef/pull/7868) ([tas50](https://github.com/tas50)) <!-- 15.0.37 --> +- Remove knife user support for open source Chef Server < 12 [#7841](https://github.com/chef/chef/pull/7841) ([tas50](https://github.com/tas50)) <!-- 15.0.36 --> +- Add additional github issue templates [#7859](https://github.com/chef/chef/pull/7859) ([tas50](https://github.com/tas50)) <!-- 15.0.35 --> +- Chef 15 node attribute array fixes [#7840](https://github.com/chef/chef/pull/7840) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 15.0.34 --> +- Remove the check for nil code property in the script provider [#7855](https://github.com/chef/chef/pull/7855) ([tas50](https://github.com/tas50)) <!-- 15.0.33 --> - powershell_package doc update [#7857](https://github.com/chef/chef/pull/7857) ([Happycoil](https://github.com/Happycoil)) <!-- 15.0.32 --> - Set http_disable_auth_on_redirect to true [#7856](https://github.com/chef/chef/pull/7856) ([tas50](https://github.com/tas50)) <!-- 15.0.31 --> - Bump inspec-core to 3.0.25 [#7853](https://github.com/chef/chef/pull/7853) ([chef-ci](https://github.com/chef-ci)) <!-- 15.0.30 --> diff --git a/Gemfile.lock b/Gemfile.lock index 108b5b988d..c474d00ceb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -27,10 +27,10 @@ GIT PATH remote: . specs: - chef (15.0.32) + chef (15.0.40) addressable bundler (>= 1.10) - chef-config (= 15.0.32) + chef-config (= 15.0.40) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -57,10 +57,10 @@ PATH specinfra (~> 2.10) syslog-logger (~> 1.6) uuidtools (~> 2.1.5) - chef (15.0.32-universal-mingw32) + chef (15.0.40-universal-mingw32) addressable bundler (>= 1.10) - chef-config (= 15.0.32) + chef-config (= 15.0.40) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -104,7 +104,7 @@ PATH PATH remote: chef-config specs: - chef-config (15.0.32) + chef-config (15.0.40) addressable fuzzyurl mixlib-config (>= 2.2.12, < 3.0) @@ -1 +1 @@ -15.0.32
\ No newline at end of file +15.0.40
\ No newline at end of file diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb index c3192757e6..4351e316ed 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 = "15.0.32".freeze + VERSION = "15.0.40".freeze end # diff --git a/lib/chef/knife/config_list_profiles.rb b/lib/chef/knife/config_list_profiles.rb index 8e46aef14b..b767e9dd42 100644 --- a/lib/chef/knife/config_list_profiles.rb +++ b/lib/chef/knife/config_list_profiles.rb @@ -21,7 +21,7 @@ require "chef/workstation_config_loader" class Chef class Knife class ConfigListProfiles < Knife - banner "knife config list-profiles" + banner "knife config list-profiles (options)" option :ignore_knife_rb, short: "-i", diff --git a/lib/chef/knife/list.rb b/lib/chef/knife/list.rb index 9452478ddb..5d95790a26 100644 --- a/lib/chef/knife/list.rb +++ b/lib/chef/knife/list.rb @@ -19,7 +19,7 @@ require "chef/chef_fs/knife" class Chef class Knife class List < Chef::ChefFS::Knife - banner "knife list [-dfR1p] [PATTERN1 ... PATTERNn]" + banner "knife list [-dfR1p] [PATTERN1 ... PATTERNn] (options)" category "path-based" diff --git a/lib/chef/knife/osc_user_create.rb b/lib/chef/knife/osc_user_create.rb deleted file mode 100644 index 97da785098..0000000000 --- a/lib/chef/knife/osc_user_create.rb +++ /dev/null @@ -1,97 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-2016, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "chef/knife" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_create.rb. -class Chef - class Knife - class OscUserCreate < Knife - - deps do - require "chef/user" - require "chef/json_compat" - end - - option :file, - short: "-f FILE", - long: "--file FILE", - description: "Write the private key to a file." - - option :admin, - short: "-a", - long: "--admin", - description: "Create the user as an admin.", - boolean: true - - option :user_password, - short: "-p PASSWORD", - long: "--password PASSWORD", - description: "Password for newly created user.", - default: "" - - option :user_key, - long: "--user-key FILENAME", - description: "Public key for newly created user. By default a key will be created for you." - - banner "knife osc_user create USER (options)" - - def run - @user_name = @name_args[0] - - if @user_name.nil? - show_usage - ui.fatal("You must specify a user name") - exit 1 - end - - if config[:user_password].length == 0 - show_usage - ui.fatal("You must specify a non-blank password") - exit 1 - end - - user = Chef::User.new - user.name(@user_name) - user.admin(config[:admin]) - user.password config[:user_password] - - if config[:user_key] - user.public_key File.read(File.expand_path(config[:user_key])) - end - - output = edit_hash(user) - user = Chef::User.from_hash(output).create - - ui.info("Created #{user}") - if user.private_key - if config[:file] - File.open(config[:file], "w") do |f| - f.print(user.private_key) - end - else - ui.msg user.private_key - end - end - end - end - end -end diff --git a/lib/chef/knife/osc_user_delete.rb b/lib/chef/knife/osc_user_delete.rb deleted file mode 100644 index 51abc1c668..0000000000 --- a/lib/chef/knife/osc_user_delete.rb +++ /dev/null @@ -1,51 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-2016, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "chef/knife" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in the user_delete.rb. - -class Chef - class Knife - class OscUserDelete < Knife - - deps do - require "chef/user" - require "chef/json_compat" - end - - banner "knife osc_user delete USER (options)" - - def run - @user_name = @name_args[0] - - if @user_name.nil? - show_usage - ui.fatal("You must specify a user name") - exit 1 - end - - delete_object(Chef::User, @user_name) - end - - end - end -end diff --git a/lib/chef/knife/osc_user_edit.rb b/lib/chef/knife/osc_user_edit.rb deleted file mode 100644 index dad90199f5..0000000000 --- a/lib/chef/knife/osc_user_edit.rb +++ /dev/null @@ -1,58 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-2018, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "chef/knife" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_edit.rb. - -class Chef - class Knife - class OscUserEdit < Knife - - deps do - require "chef/user" - require "chef/json_compat" - end - - banner "knife osc_user edit USER (options)" - - def run - @user_name = @name_args[0] - - if @user_name.nil? - show_usage - ui.fatal("You must specify a user name") - exit 1 - end - - original_user = Chef::User.load(@user_name).to_h - edited_user = edit_hash(original_user) - if original_user != edited_user - user = Chef::User.from_hash(edited_user) - user.update - ui.msg("Saved #{user}.") - else - ui.msg("User unchanged, not saving.") - end - end - end - end -end diff --git a/lib/chef/knife/osc_user_list.rb b/lib/chef/knife/osc_user_list.rb deleted file mode 100644 index 3e22bbb1c4..0000000000 --- a/lib/chef/knife/osc_user_list.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-2016, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "chef/knife" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_list.rb. - -class Chef - class Knife - class OscUserList < Knife - - deps do - require "chef/user" - require "chef/json_compat" - end - - banner "knife osc_user list (options)" - - option :with_uri, - short: "-w", - long: "--with-uri", - description: "Show corresponding URIs." - - def run - output(format_list_for_display(Chef::User.list)) - end - end - end -end diff --git a/lib/chef/knife/osc_user_reregister.rb b/lib/chef/knife/osc_user_reregister.rb deleted file mode 100644 index 4e4a575222..0000000000 --- a/lib/chef/knife/osc_user_reregister.rb +++ /dev/null @@ -1,64 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-2016, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "chef/knife" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_reregister.rb. - -class Chef - class Knife - class OscUserReregister < Knife - - deps do - require "chef/user" - require "chef/json_compat" - end - - banner "knife osc_user reregister USER (options)" - - option :file, - short: "-f FILE", - long: "--file FILE", - description: "Write the private key to a file." - - def run - @user_name = @name_args[0] - - if @user_name.nil? - show_usage - ui.fatal("You must specify a user name") - exit 1 - end - - user = Chef::User.load(@user_name).reregister - Chef::Log.trace("Updated user data: #{user.inspect}") - key = user.private_key - if config[:file] - File.open(config[:file], "w") do |f| - f.print(key) - end - else - ui.msg key - end - end - end - end -end diff --git a/lib/chef/knife/osc_user_show.rb b/lib/chef/knife/osc_user_show.rb deleted file mode 100644 index 5350837ad3..0000000000 --- a/lib/chef/knife/osc_user_show.rb +++ /dev/null @@ -1,53 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2009-2016, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "chef/knife" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_show.rb. - -class Chef - class Knife - class OscUserShow < Knife - - include Knife::Core::MultiAttributeReturnOption - - deps do - require "chef/user" - require "chef/json_compat" - end - - banner "knife osc_user show USER (options)" - - def run - @user_name = @name_args[0] - - if @user_name.nil? - show_usage - ui.fatal("You must specify a user name") - exit 1 - end - - user = Chef::User.load(@user_name) - output(format_for_display(user)) - end - end - end -end diff --git a/lib/chef/knife/raw.rb b/lib/chef/knife/raw.rb index 5658420c3e..a544dcbfdd 100644 --- a/lib/chef/knife/raw.rb +++ b/lib/chef/knife/raw.rb @@ -20,7 +20,7 @@ require "chef/http" class Chef class Knife class Raw < Chef::Knife - banner "knife raw REQUEST_PATH" + banner "knife raw REQUEST_PATH (options)" deps do require "chef/json_compat" diff --git a/lib/chef/knife/role_env_run_list_clear.rb b/lib/chef/knife/role_env_run_list_clear.rb index d9dc96c87d..ecc41347eb 100644 --- a/lib/chef/knife/role_env_run_list_clear.rb +++ b/lib/chef/knife/role_env_run_list_clear.rb @@ -28,7 +28,7 @@ class Chef require "chef/json_compat" end - banner "knife role env_run_list clear [ROLE] [ENVIRONMENT]" + banner "knife role env_run_list clear [ROLE] [ENVIRONMENT] (options)" def clear_env_run_list(role, environment) nlist = [] role.env_run_lists_add(environment => nlist) diff --git a/lib/chef/knife/role_env_run_list_remove.rb b/lib/chef/knife/role_env_run_list_remove.rb index f31f40b58a..9b627a00fc 100644 --- a/lib/chef/knife/role_env_run_list_remove.rb +++ b/lib/chef/knife/role_env_run_list_remove.rb @@ -27,7 +27,7 @@ class Chef require "chef/json_compat" end - banner "knife role env_run_list remove [ROLE] [ENVIRONMENT] [ENTRIES]" + banner "knife role env_run_list remove [ROLE] [ENVIRONMENT] [ENTRIES] (options)" def remove_from_env_run_list(role, environment, item_to_remove) nlist = [] diff --git a/lib/chef/knife/role_env_run_list_replace.rb b/lib/chef/knife/role_env_run_list_replace.rb index e4b6179b65..f4e4dfec66 100644 --- a/lib/chef/knife/role_env_run_list_replace.rb +++ b/lib/chef/knife/role_env_run_list_replace.rb @@ -28,7 +28,7 @@ class Chef require "chef/json_compat" end - banner "knife role env_run_list replace [ROLE] [ENVIRONMENT] [OLD_ENTRY] [NEW_ENTRY] " + banner "knife role env_run_list replace [ROLE] [ENVIRONMENT] [OLD_ENTRY] [NEW_ENTRY] (options)" def replace_in_env_run_list(role, environment, old_entry, new_entry) nlist = [] diff --git a/lib/chef/knife/role_env_run_list_set.rb b/lib/chef/knife/role_env_run_list_set.rb index f53616e151..fd8afd6652 100644 --- a/lib/chef/knife/role_env_run_list_set.rb +++ b/lib/chef/knife/role_env_run_list_set.rb @@ -28,7 +28,7 @@ class Chef require "chef/json_compat" end - banner "knife role env_run_list set [ROLE] [ENVIRONMENT] [ENTRIES]" + banner "knife role env_run_list set [ROLE] [ENVIRONMENT] [ENTRIES] (optionss)" # Clears out any existing env_run_list_items and sets them to the # specified entries diff --git a/lib/chef/knife/role_run_list_clear.rb b/lib/chef/knife/role_run_list_clear.rb index 81678d39ef..a3fde43875 100644 --- a/lib/chef/knife/role_run_list_clear.rb +++ b/lib/chef/knife/role_run_list_clear.rb @@ -28,7 +28,7 @@ class Chef require "chef/json_compat" end - banner "knife role run_list clear [ROLE]" + banner "knife role run_list clear [ROLE] (options)" def clear_env_run_list(role, environment) nlist = [] role.env_run_lists_add(environment => nlist) diff --git a/lib/chef/knife/role_run_list_remove.rb b/lib/chef/knife/role_run_list_remove.rb index 8aaf408a61..39e935605e 100644 --- a/lib/chef/knife/role_run_list_remove.rb +++ b/lib/chef/knife/role_run_list_remove.rb @@ -26,7 +26,7 @@ class Chef require "chef/role" end - banner "knife role run_list remove [ROLE] [ENTRY]" + banner "knife role run_list remove [ROLE] [ENTRY] (options)" def remove_from_env_run_list(role, environment, item_to_remove) nlist = [] diff --git a/lib/chef/knife/role_run_list_replace.rb b/lib/chef/knife/role_run_list_replace.rb index 64b5790d9d..bb93661548 100644 --- a/lib/chef/knife/role_run_list_replace.rb +++ b/lib/chef/knife/role_run_list_replace.rb @@ -28,7 +28,7 @@ class Chef require "chef/json_compat" end - banner "knife role run_list replace [ROLE] [OLD_ENTRY] [NEW_ENTRY] " + banner "knife role run_list replace [ROLE] [OLD_ENTRY] [NEW_ENTRY] (options)" def replace_in_env_run_list(role, environment, old_entry, new_entry) nlist = [] diff --git a/lib/chef/knife/role_run_list_set.rb b/lib/chef/knife/role_run_list_set.rb index 87ba3efb1f..d424bad7e6 100644 --- a/lib/chef/knife/role_run_list_set.rb +++ b/lib/chef/knife/role_run_list_set.rb @@ -27,7 +27,7 @@ class Chef require "chef/role" end - banner "knife role run_list set [ROLE] [ENTRIES]" + banner "knife role run_list set [ROLE] [ENTRIES] (options)" # Clears out any existing env_run_list_items and sets them to the # specified entries diff --git a/lib/chef/knife/show.rb b/lib/chef/knife/show.rb index e31a2c1b0c..10a1d521e3 100644 --- a/lib/chef/knife/show.rb +++ b/lib/chef/knife/show.rb @@ -19,7 +19,7 @@ require "chef/chef_fs/knife" class Chef class Knife class Show < Chef::ChefFS::Knife - banner "knife show [PATTERN1 ... PATTERNn]" + banner "knife show [PATTERN1 ... PATTERNn] (options)" category "path-based" diff --git a/lib/chef/knife/upload.rb b/lib/chef/knife/upload.rb index 9b651ae867..25dcd81004 100644 --- a/lib/chef/knife/upload.rb +++ b/lib/chef/knife/upload.rb @@ -19,7 +19,7 @@ require "chef/chef_fs/knife" class Chef class Knife class Upload < Chef::ChefFS::Knife - banner "knife upload PATTERNS" + banner "knife upload PATTERNS (options)" category "path-based" diff --git a/lib/chef/knife/user_create.rb b/lib/chef/knife/user_create.rb index 3553e4db44..6a4a123ad8 100644 --- a/lib/chef/knife/user_create.rb +++ b/lib/chef/knife/user_create.rb @@ -18,7 +18,6 @@ # require "chef/knife" -require "chef/knife/osc_user_create" class Chef class Knife @@ -45,18 +44,6 @@ class Chef description: "API V1 (Chef Server 12.1+) only. Prevent server from generating a default key pair for you. Cannot be passed with --user-key.", boolean: true - option :admin, - short: "-a", - long: "--admin", - description: "DEPRECATED: Open Source Chef 11 only. Create the user as an admin.", - boolean: true - - option :user_password, - short: "-p PASSWORD", - long: "--password PASSWORD", - description: "DEPRECATED: Open Source Chef 11 only. Password for newly created user.", - default: "" - banner "knife user create USERNAME DISPLAY_NAME FIRST_NAME LAST_NAME EMAIL PASSWORD (options)" def user @@ -67,82 +54,50 @@ class Chef Chef::UserV1.from_hash(hash).create end - def osc_11_warning - <<~EOF - IF YOU ARE USING CHEF SERVER 12+, PLEASE FOLLOW THE INSTRUCTIONS UNDER knife user create --help. - You only passed a single argument to knife user create. - For backwards compatibility, when only a single argument is passed, - knife user create assumes you want Open Source 11 Server user creation. - knife user create for Open Source 11 Server is being deprecated. - Open Source 11 Server user commands now live under the knife osc_user namespace. - For backwards compatibility, we will forward this request to knife osc_user create. - If you are using an Open Source 11 Server, please use that command to avoid this warning. - NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed - in Chef 15 which will be released April 2019. -EOF - end - - def run_osc_11_user_create - # run osc_user_create with our input - ARGV.delete("user") - ARGV.unshift("osc_user") - Chef::Knife.run(ARGV, Chef::Application::Knife.options) - end - def run - # DEPRECATION NOTE - # Remove this if statement and corrosponding code post OSC 11 support. - # - # If only 1 arg is passed, assume OSC 11 case. - if @name_args.length == 1 - ui.warn(osc_11_warning) - run_osc_11_user_create - else # EC / CS 12 user create + test_mandatory_field(@name_args[0], "username") + user.username @name_args[0] - test_mandatory_field(@name_args[0], "username") - user.username @name_args[0] + test_mandatory_field(@name_args[1], "display name") + user.display_name @name_args[1] - test_mandatory_field(@name_args[1], "display name") - user.display_name @name_args[1] + test_mandatory_field(@name_args[2], "first name") + user.first_name @name_args[2] - test_mandatory_field(@name_args[2], "first name") - user.first_name @name_args[2] + test_mandatory_field(@name_args[3], "last name") + user.last_name @name_args[3] - test_mandatory_field(@name_args[3], "last name") - user.last_name @name_args[3] + test_mandatory_field(@name_args[4], "email") + user.email @name_args[4] - test_mandatory_field(@name_args[4], "email") - user.email @name_args[4] + test_mandatory_field(@name_args[5], "password") + user.password @name_args[5] - test_mandatory_field(@name_args[5], "password") - user.password @name_args[5] + if config[:user_key] && config[:prevent_keygen] + show_usage + ui.fatal("You cannot pass --user-key and --prevent-keygen") + exit 1 + end - if config[:user_key] && config[:prevent_keygen] - show_usage - ui.fatal("You cannot pass --user-key and --prevent-keygen") - exit 1 - end + if !config[:prevent_keygen] && !config[:user_key] + user.create_key(true) + end - if !config[:prevent_keygen] && !config[:user_key] - user.create_key(true) - end + if config[:user_key] + user.public_key File.read(File.expand_path(config[:user_key])) + end - if config[:user_key] - user.public_key File.read(File.expand_path(config[:user_key])) - end + output = edit_hash(user) + final_user = create_user_from_hash(output) - output = edit_hash(user) - final_user = create_user_from_hash(output) - - ui.info("Created #{user}") - if final_user.private_key - if config[:file] - File.open(config[:file], "w") do |f| - f.print(final_user.private_key) - end - else - ui.msg final_user.private_key + ui.info("Created #{user}") + if final_user.private_key + if config[:file] + File.open(config[:file], "w") do |f| + f.print(final_user.private_key) end + else + ui.msg final_user.private_key end end end diff --git a/lib/chef/knife/user_delete.rb b/lib/chef/knife/user_delete.rb index 38122975c7..2638d2cce3 100644 --- a/lib/chef/knife/user_delete.rb +++ b/lib/chef/knife/user_delete.rb @@ -28,42 +28,6 @@ class Chef banner "knife user delete USER (options)" - def osc_11_warning - <<~EOF - The Chef Server you are using does not support the username field. - This means it is an Open Source 11 Server. - knife user delete for Open Source 11 Server is being deprecated. - Open Source 11 Server user commands now live under the knife osc_user namespace. - For backwards compatibility, we will forward this request to knife osc_user delete. - If you are using an Open Source 11 Server, please use that command to avoid this warning. - NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed - in Chef 15 which will be released April 2019. -EOF - end - - def run_osc_11_user_delete - # run osc_user_delete with our input - ARGV.delete("user") - ARGV.unshift("osc_user") - Chef::Knife.run(ARGV, Chef::Application::Knife.options) - end - - # DEPRECATION NOTE - # Delete this override method after OSC 11 support is dropped - def delete_object(user_name) - confirm("Do you really want to delete #{user_name}") - - if Kernel.block_given? - object = block.call - else - object = Chef::UserV1.load(user_name) - object.destroy - end - - output(format_for_display(object)) if config[:print_after] - msg("Deleted #{user_name}") - end - def run @user_name = @name_args[0] @@ -73,23 +37,7 @@ EOF exit 1 end - # DEPRECATION NOTE - # - # Below is modification of Chef::Knife.delete_object to detect OSC 11 server. - # When OSC 11 is deprecated, simply delete all this and go back to: - # - # delete_object(Chef::UserV1, @user_name) - # - # Also delete our override of delete_object above - object = Chef::UserV1.load(@user_name) - - # OSC 11 case - if object.username.nil? - ui.warn(osc_11_warning) - run_osc_11_user_delete - else # proceed with EC / CS delete - delete_object(@user_name) - end + delete_object(Chef::UserV1, @user_name) end end end diff --git a/lib/chef/knife/user_edit.rb b/lib/chef/knife/user_edit.rb index eb6d74c470..a039525001 100644 --- a/lib/chef/knife/user_edit.rb +++ b/lib/chef/knife/user_edit.rb @@ -28,26 +28,6 @@ class Chef banner "knife user edit USER (options)" - def osc_11_warning - <<~EOF - The Chef Server you are using does not support the username field. - This means it is an Open Source 11 Server. - knife user edit for Open Source 11 Server is being deprecated. - Open Source 11 Server user commands now live under the knife oc_user namespace. - For backwards compatibility, we will forward this request to knife osc_user edit. - If you are using an Open Source 11 Server, please use that command to avoid this warning. - NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed - in Chef 15 which will be released April 2019. -EOF - end - - def run_osc_11_user_edit - # run osc_user_create with our input - ARGV.delete("user") - ARGV.unshift("osc_user") - Chef::Knife.run(ARGV, Chef::Application::Knife.options) - end - def run @user_name = @name_args[0] @@ -57,24 +37,14 @@ EOF exit 1 end - original_user = Chef::UserV1.load(@user_name).to_h - # DEPRECATION NOTE - # Remove this if statement and corrosponding code post OSC 11 support. - # - # if username is nil, we are in the OSC 11 case, - # forward to deprecated command - if original_user["username"].nil? - ui.warn(osc_11_warning) - run_osc_11_user_edit - else # EC / CS 12 user create - edited_user = edit_hash(original_user) - if original_user != edited_user - user = Chef::UserV1.from_hash(edited_user) - user.update - ui.msg("Saved #{user}.") - else - ui.msg("User unchanged, not saving.") - end + original_user = Chef::UserV1.load(@user_name).to_hash + edited_user = edit_hash(original_user) + if original_user != edited_user + user = Chef::UserV1.from_hash(edited_user) + user.update + ui.msg("Saved #{user}.") + else + ui.msg("User unchanged, not saving.") end end end diff --git a/lib/chef/knife/user_list.rb b/lib/chef/knife/user_list.rb index c1c0fa5109..31758ce117 100644 --- a/lib/chef/knife/user_list.rb +++ b/lib/chef/knife/user_list.rb @@ -18,8 +18,6 @@ require "chef/knife" -# NOTE: only knife user command that is backwards compatible with OSC 11, -# so no deprecation warnings are necessary. class Chef class Knife class UserList < Knife diff --git a/lib/chef/knife/user_reregister.rb b/lib/chef/knife/user_reregister.rb index 97840cadf3..3c63c32f29 100644 --- a/lib/chef/knife/user_reregister.rb +++ b/lib/chef/knife/user_reregister.rb @@ -28,26 +28,6 @@ class Chef banner "knife user reregister USER (options)" - def osc_11_warning - <<~EOF - The Chef Server you are using does not support the username field. - This means it is an Open Source 11 Server. - knife user reregister for Open Source 11 Server is being deprecated. - Open Source 11 Server user commands now live under the knife osc_user namespace. - For backwards compatibility, we will forward this request to knife osc_user reregister. - If you are using an Open Source 11 Server, please use that command to avoid this warning. - NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed - in Chef 15 which will be released April 2019. -EOF - end - - def run_osc_11_user_reregister - # run osc_user_edit with our input - ARGV.delete("user") - ARGV.unshift("osc_user") - Chef::Knife.run(ARGV, Chef::Application::Knife.options) - end - option :file, short: "-f FILE", long: "--file FILE", @@ -63,26 +43,15 @@ EOF end user = Chef::UserV1.load(@user_name) - - # DEPRECATION NOTE - # Remove this if statement and corrosponding code post OSC 11 support. - # - # if username is nil, we are in the OSC 11 case, - # forward to deprecated command - if user.username.nil? - ui.warn(osc_11_warning) - run_osc_11_user_reregister - else # EC / CS 12 case - user.reregister - Chef::Log.trace("Updated user data: #{user.inspect}") - key = user.private_key - if config[:file] - File.open(config[:file], "w") do |f| - f.print(key) - end - else - ui.msg key + user.reregister + Chef::Log.trace("Updated user data: #{user.inspect}") + key = user.private_key + if config[:file] + File.open(config[:file], "w") do |f| + f.print(key) end + else + ui.msg key end end end diff --git a/lib/chef/knife/user_show.rb b/lib/chef/knife/user_show.rb index 544d420346..a27549aea7 100644 --- a/lib/chef/knife/user_show.rb +++ b/lib/chef/knife/user_show.rb @@ -30,26 +30,6 @@ class Chef banner "knife user show USER (options)" - def osc_11_warning - <<~EOF - The Chef Server you are using does not support the username field. - This means it is an Open Source 11 Server. - knife user show for Open Source 11 Server is being deprecated. - Open Source 11 Server user commands now live under the knife osc_user namespace. - For backwards compatibility, we will forward this request to knife osc_user show. - If you are using an Open Source 11 Server, please use that command to avoid this warning. - NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed - in Chef 15 which will be released April 2019. -EOF - end - - def run_osc_11_user_show - # run osc_user_edit with our input - ARGV.delete("user") - ARGV.unshift("osc_user") - Chef::Knife.run(ARGV, Chef::Application::Knife.options) - end - def run @user_name = @name_args[0] @@ -60,18 +40,7 @@ EOF end user = Chef::UserV1.load(@user_name) - - # DEPRECATION NOTE - # Remove this if statement and corrosponding code post OSC 11 support. - # - # if username is nil, we are in the OSC 11 case, - # forward to deprecated command - if user.username.nil? - ui.warn(osc_11_warning) - run_osc_11_user_show - else - output(format_for_display(user)) - end + output(format_for_display(user)) end end diff --git a/lib/chef/knife/xargs.rb b/lib/chef/knife/xargs.rb index a5ced3eea8..ae5851f465 100644 --- a/lib/chef/knife/xargs.rb +++ b/lib/chef/knife/xargs.rb @@ -19,7 +19,7 @@ require "chef/chef_fs/knife" class Chef class Knife class Xargs < Chef::ChefFS::Knife - banner "knife xargs [COMMAND]" + banner "knife xargs [COMMAND] (options)" category "path-based" diff --git a/lib/chef/node/attribute_collections.rb b/lib/chef/node/attribute_collections.rb index f62eceb646..382ecfba91 100644 --- a/lib/chef/node/attribute_collections.rb +++ b/lib/chef/node/attribute_collections.rb @@ -18,6 +18,9 @@ require "chef/node/common_api" require "chef/node/mixin/state_tracking" +require "chef/node/mixin/immutablize_array" +require "chef/node/mixin/immutablize_hash" +require "chef/node/mixin/mashy_array" class Chef class Node @@ -26,36 +29,9 @@ class Chef # "root" (Chef::Node::Attribute) object, and will trigger a cache # invalidation on that object when mutated. class AttrArray < Array - MUTATOR_METHODS = [ - :<<, - :[]=, - :clear, - :collect!, - :compact!, - :default=, - :default_proc=, - :delete_at, - :delete_if, - :fill, - :flatten!, - :insert, - :keep_if, - :map!, - :merge!, - :pop, - :push, - :update, - :reject!, - :reverse!, - :replace, - :select!, - :shift, - :slice!, - :sort!, - :sort_by!, - :uniq!, - :unshift, - ].freeze + include Chef::Node::Mixin::MashyArray + + MUTATOR_METHODS = Chef::Node::Mixin::ImmutablizeArray::DISALLOWED_MUTATOR_METHODS # For all of the methods that may mutate an Array, we override them to # also invalidate the cached merged_attributes on the root @@ -130,27 +106,11 @@ class Chef # Methods that mutate a VividMash. Each of them is overridden so that it # also invalidates the cached merged_attributes on the root Attribute # object. - MUTATOR_METHODS = [ - :clear, - :delete_if, - :keep_if, - :merge!, - :update, - :reject!, - :replace, - :select!, - :shift, - ].freeze + MUTATOR_METHODS = Chef::Node::Mixin::ImmutablizeHash::DISALLOWED_MUTATOR_METHODS - [ :write, :write!, :unlink, :unlink! ] # For all of the mutating methods on Mash, override them so that they # also invalidate the cached `merged_attributes` on the root Attribute # object. - - def delete(key, &block) - send_reset_cache(__path__, key) - super - end - MUTATOR_METHODS.each do |mutator| define_method(mutator) do |*args, &block| send_reset_cache @@ -158,6 +118,11 @@ class Chef end end + def delete(key, &block) + send_reset_cache(__path__, key) + super + end + def initialize(data = {}) super(data) end diff --git a/lib/chef/node/mixin/immutablize_array.rb b/lib/chef/node/mixin/immutablize_array.rb index 000a088410..b5e0993cfa 100644 --- a/lib/chef/node/mixin/immutablize_array.rb +++ b/lib/chef/node/mixin/immutablize_array.rb @@ -159,7 +159,6 @@ class Chef :sort_by!, :uniq!, :unshift, - :update, ].freeze # Redefine all of the methods that mutate a Hash to raise an error when called. diff --git a/lib/chef/node/mixin/mashy_array.rb b/lib/chef/node/mixin/mashy_array.rb new file mode 100644 index 0000000000..31506c5bbf --- /dev/null +++ b/lib/chef/node/mixin/mashy_array.rb @@ -0,0 +1,68 @@ +#-- +# Copyright:: Copyright 2016-2018, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + class Node + module Mixin + # missing methods for Arrays similar to Chef::Mash methods that call + # convert_value correctly. + module MashyArray + def <<(obj) + super(convert_value(obj)) + end + + def []=(*keys, value) + super(*keys, convert_value(value)) + end + + def push(*objs) + objs = objs.map { |obj| convert_value(obj) } + super(*objs) + end + + def unshift(*objs) + objs = objs.map { |obj| convert_value(obj) } + super(*objs) + end + + def insert(index, *objs) + objs = objs.map { |obj| convert_value(obj) } + super(index, *objs) + end + + def collect!(&block) + super + map! { |x| convert_value(x) } + end + + def map!(&block) + super + super { |x| convert_value(x) } + end + + def fill(*args, &block) + super + map! { |x| convert_value(x) } + end + + def replace(obj) + super(convert_value(obj)) + end + end + end + end +end diff --git a/lib/chef/provider/script.rb b/lib/chef/provider/script.rb index 444eac54ac..b54965be45 100644 --- a/lib/chef/provider/script.rb +++ b/lib/chef/provider/script.rb @@ -49,10 +49,6 @@ class Chef def load_current_resource super - # @todo Chef-15: change this to an exception - if code.nil? - logger.warn "#{new_resource}: No code attribute was given, resource does nothing, this behavior is deprecated and will be removed in Chef 15 (April 2019)" - end end def action_run diff --git a/lib/chef/resource/apt_preference.rb b/lib/chef/resource/apt_preference.rb index 0169fb73c2..7ece829ba2 100644 --- a/lib/chef/resource/apt_preference.rb +++ b/lib/chef/resource/apt_preference.rb @@ -31,7 +31,8 @@ class Chef property :package_name, String, name_property: true, description: "The name of the package.", - regex: [/^([a-z]|[A-Z]|[0-9]|_|-|\.|\*|\+)+$/] + regex: [/^([a-z]|[A-Z]|[0-9]|_|-|\.|\*|\+)+$/], + validation_message: "The provided package name is not valid. Package names can only contain alphanumeric characters as well as _, -, +, or *!" property :glob, String, description: "Pin by glob() expression or with regular expressions surrounded by /." diff --git a/lib/chef/resource/apt_update.rb b/lib/chef/resource/apt_update.rb index 04a9407813..680806bc26 100644 --- a/lib/chef/resource/apt_update.rb +++ b/lib/chef/resource/apt_update.rb @@ -29,6 +29,7 @@ class Chef # allow bare apt_update with no name property :name, String, default: "" + property :frequency, Integer, description: "Determines how frequently (in seconds) APT repository updates are made. Use this property when the :periodic action is specified.", default: 86_400 diff --git a/lib/chef/resource/build_essential.rb b/lib/chef/resource/build_essential.rb index 99722b14ed..d9d75fb83b 100644 --- a/lib/chef/resource/build_essential.rb +++ b/lib/chef/resource/build_essential.rb @@ -30,7 +30,7 @@ class Chef property :compile_time, [TrueClass, FalseClass], description: "Install the build essential packages at compile time.", - default: false + default: false, desired_state: false action :install do diff --git a/lib/chef/resource/cab_package.rb b/lib/chef/resource/cab_package.rb index a90ddc6891..501a0dfa26 100644 --- a/lib/chef/resource/cab_package.rb +++ b/lib/chef/resource/cab_package.rb @@ -39,7 +39,7 @@ class Chef uri_scheme?(s) ? s : Chef::Util::PathHelper.canonical_path(s, false) end end), - default: lazy { |r| r.package_name } + default: lazy { |r| r.package_name }, default_description: "The package name." end end end diff --git a/lib/chef/resource/chef_gem.rb b/lib/chef/resource/chef_gem.rb index 0a1b2ef736..6758a0c753 100644 --- a/lib/chef/resource/chef_gem.rb +++ b/lib/chef/resource/chef_gem.rb @@ -36,7 +36,7 @@ class Chef class ChefGem < Chef::Resource::Package::GemPackage resource_name :chef_gem - property :gem_binary, default: "#{RbConfig::CONFIG['bindir']}/gem", + property :gem_binary, default: "#{RbConfig::CONFIG['bindir']}/gem", default_description: "Chef's built-in gem binary.", description: "The path of a gem binary to use for the installation. By default, the same version of Ruby that is used by the chef-client will be installed.", callbacks: { "The chef_gem resource is restricted to the current gem environment, use gem_package to install to other environments." => proc { |v| v == "#{RbConfig::CONFIG['bindir']}/gem" }, diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb index 0caa9d0553..c96e794469 100644 --- a/lib/chef/resource/cookbook_file.rb +++ b/lib/chef/resource/cookbook_file.rb @@ -36,7 +36,8 @@ class Chef default: lazy { ::File.basename(name) } property :cookbook, String, - description: "The cookbook in which a file is located (if it is not located in the current cookbook)." + description: "The cookbook in which a file is located (if it is not located in the current cookbook).", + desired_state: false default_action :create end diff --git a/lib/chef/resource/cron_d.rb b/lib/chef/resource/cron_d.rb index 304a1ad388..a42e3e0246 100644 --- a/lib/chef/resource/cron_d.rb +++ b/lib/chef/resource/cron_d.rb @@ -90,7 +90,7 @@ class Chef description: "Set the name of the cron job. If this isn't specified we'll use the resource name.", name_property: true - property :cookbook, String + property :cookbook, String, desired_state: false property :predefined_value, String, description: 'Schedule your cron job with one of the special predefined value instead of ** * pattern. This correspond to "@reboot", "@yearly", "@annually", "@monthly", "@weekly", "@daily", "@midnight" or "@hourly".', diff --git a/lib/chef/resource/dmg_package.rb b/lib/chef/resource/dmg_package.rb index 17645e519b..cd2f0b5c3a 100644 --- a/lib/chef/resource/dmg_package.rb +++ b/lib/chef/resource/dmg_package.rb @@ -48,12 +48,12 @@ class Chef property :volumes_dir, String, description: "The Directory under /Volumes where the dmg is mounted as not all dmgs are mounted into a /Volumes location matching the name of the dmg.", - default: lazy { |r| r.app } + default: lazy { |r| r.app }, default_description: "The value passed for the application name." property :dmg_name, String, description: "The name of the dmg if it is not the same as app, or if the name has spaces.", desired_state: false, - default: lazy { |r| r.app } + default: lazy { |r| r.app }, default_description: "The value passed for the application name." property :type, String, description: "The type of package.", diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index 1becbf50a7..e74d0c1439 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -62,7 +62,7 @@ class Chef description: "Prevent a command from creating a file when that file already exists." property :cwd, String, - description: "Set the current working directory before running a command." + description: "The current working directory from which the command will be run." property :environment, Hash, description: "Specify a Hash of environment variables to be set." @@ -100,7 +100,7 @@ class Chef # lazy used to set default value of sensitive to true if password is set property :sensitive, [ TrueClass, FalseClass ], description: "Ensure that sensitive resource data is not logged by the chef-client.", - default: lazy { |r| r.password ? true : false } + default: lazy { |r| r.password ? true : false }, default_description: "True if the password property is set. False otherwise." property :elevated, [ TrueClass, FalseClass ], default: false, description: "Determines whether the script will run with elevated permissions to circumvent User Access Control (UAC) interactively blocking the process.\nThis will cause the process to be run under a batch login instead of an interactive login. The user running Chef needs the “Replace a process level token” and “Adjust Memory Quotas for a process” permissions. The user that is running the command needs the “Log on as a batch job” permission.\nBecause this requires a login, the user and password properties are required.", diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb index cac20f2356..8db15fc661 100644 --- a/lib/chef/resource/file.rb +++ b/lib/chef/resource/file.rb @@ -66,7 +66,7 @@ class Chef property :content, [ String, nil ], desired_state: false, description: "A string that is written to the file. The contents of this property replace any previous content when this property has something other than the default value. The default behavior will not modify content." - property :diff, [ String, nil ], desired_state: false + property :diff, [ String, nil ], desired_state: false, skip_docs: true property :force_unlink, [ TrueClass, FalseClass ], desired_state: false, default: false, description: "How the chef-client handles certain situations when the target file turns out not to be a file. For example, when a target file is actually a symlink. Set to true for the chef-client delete the non-file target and replace it with the specified file. Set to false for the chef-client to raise an error." diff --git a/lib/chef/resource/homebrew_cask.rb b/lib/chef/resource/homebrew_cask.rb index 626ae02a69..7c47fbbfcd 100644 --- a/lib/chef/resource/homebrew_cask.rb +++ b/lib/chef/resource/homebrew_cask.rb @@ -34,6 +34,7 @@ class Chef property :cask_name, String, description: "The name of the Homebrew cask, if it differs from the resource block name.", regex: %r{^[\w/-]+$}, + validation_message: "The provided Homebrew cask name is not valid. Cask names can contain alphanumeric characters, _, -, or / only!", name_property: true property :options, String, diff --git a/lib/chef/resource/homebrew_tap.rb b/lib/chef/resource/homebrew_tap.rb index 20ac0bb5d5..a4591e9ed8 100644 --- a/lib/chef/resource/homebrew_tap.rb +++ b/lib/chef/resource/homebrew_tap.rb @@ -33,7 +33,7 @@ class Chef property :tap_name, String, description: "Optional tap name to override the resource name", - validation_message: "Homebrew tap names must be in the form REPO/TAP", + validation_message: "Homebrew tap names must be in the form REPO/TAP format!", regex: %r{^[\w-]+(?:\/[\w-]+)+$}, name_property: true diff --git a/lib/chef/resource/hostname.rb b/lib/chef/resource/hostname.rb index 30446fbead..37106efd74 100644 --- a/lib/chef/resource/hostname.rb +++ b/lib/chef/resource/hostname.rb @@ -32,7 +32,7 @@ class Chef property :compile_time, [ TrueClass, FalseClass ], description: "Determines whether or not the resource shoul be run at compile time.", - default: true + default: true, desired_state: false property :ipaddress, String, description: "The IP address to use when configuring the hosts file.", diff --git a/lib/chef/resource/locale.rb b/lib/chef/resource/locale.rb index 443e682c47..ca6ea510c0 100644 --- a/lib/chef/resource/locale.rb +++ b/lib/chef/resource/locale.rb @@ -28,6 +28,7 @@ class Chef property :lang, String, default: "en_US.utf8", description: "Sets the default system language." + property :lc_all, String, default: "en_US.utf8", description: "Sets the fallback system language." diff --git a/lib/chef/resource/mdadm.rb b/lib/chef/resource/mdadm.rb index 3fc5b7c338..ee0284ec37 100644 --- a/lib/chef/resource/mdadm.rb +++ b/lib/chef/resource/mdadm.rb @@ -40,9 +40,10 @@ class Chef default: lazy { [] }, description: "The devices to be part of a RAID array." + # @todo this should get refactored away property :exists, [ TrueClass, FalseClass ], default: false, - description: "Indicates whether the RAID array exists." + skip_docs: true property :level, Integer, default: 1, diff --git a/lib/chef/resource/mount.rb b/lib/chef/resource/mount.rb index 71e23c8cdb..4c20a62cf8 100644 --- a/lib/chef/resource/mount.rb +++ b/lib/chef/resource/mount.rb @@ -50,7 +50,7 @@ class Chef equal_to: RUBY_PLATFORM =~ /solaris/i ? %i{ device } : %i{ device label uuid } # @todo this should get refactored away: https://github.com/chef/chef/issues/7621 - property :mounted, [TrueClass, FalseClass], default: false + property :mounted, [TrueClass, FalseClass], default: false, skip_docs: true property :fsck_device, String, description: "Solaris only: The fsck device.", diff --git a/lib/chef/resource/openssl_rsa_private_key.rb b/lib/chef/resource/openssl_rsa_private_key.rb index f2c1400a30..f0d54dbe37 100644 --- a/lib/chef/resource/openssl_rsa_private_key.rb +++ b/lib/chef/resource/openssl_rsa_private_key.rb @@ -36,7 +36,7 @@ class Chef property :key_length, Integer, equal_to: [1024, 2048, 4096, 8192], - validation_message: "key_length (bits) must be 1024, 2048, 4096, or 8192.", + validation_message: "key_length (bits) must be 1024, 2048, 4096, or 8192!", description: "The desired bit length of the generated key.", default: 2048 diff --git a/lib/chef/resource/powershell_package.rb b/lib/chef/resource/powershell_package.rb index 60aabb9fd0..28dabc82b0 100644 --- a/lib/chef/resource/powershell_package.rb +++ b/lib/chef/resource/powershell_package.rb @@ -45,7 +45,7 @@ class Chef property :skip_publisher_check, [true, false], description: "Skip validating module author.", - default: false, introduced: "14.3" + default: false, introduced: "14.3", desired_state: false end end diff --git a/lib/chef/resource/remote_directory.rb b/lib/chef/resource/remote_directory.rb index f03b13ef02..b9f701ee6d 100644 --- a/lib/chef/resource/remote_directory.rb +++ b/lib/chef/resource/remote_directory.rb @@ -56,8 +56,8 @@ class Chef property :source, String, default: lazy { ::File.basename(path) } property :files_backup, [ Integer, FalseClass ], default: 5, desired_state: false property :purge, [ TrueClass, FalseClass ], default: false, desired_state: false - property :overwrite, [ TrueClass, FalseClass ], default: true - property :cookbook, String + property :overwrite, [ TrueClass, FalseClass ], default: true, desired_state: false + property :cookbook, String, desired_state: false def files_group(arg = nil) set_or_return( diff --git a/lib/chef/resource/sudo.rb b/lib/chef/resource/sudo.rb index c417a4d26c..5b70ffa22d 100644 --- a/lib/chef/resource/sudo.rb +++ b/lib/chef/resource/sudo.rb @@ -37,7 +37,7 @@ class Chef # acording to the sudo man pages sudo will ignore files in an include dir that have a `.` or `~` # We convert either to `__` property :filename, String, - description: "The name of the sudoers.d file.", + description: "The name of the sudoers.d file, if it differs from the name of the resource block", name_property: true, coerce: proc { |x| x.gsub(/[\.~]/, "__") } @@ -99,15 +99,15 @@ class Chef default: lazy { [] } property :visudo_path, String, - description: "Deprecated property. Do not use." + deprecated: true property :visudo_binary, String, description: "The path to visudo for configuration verification.", default: "/usr/sbin/visudo" property :config_prefix, String, - description: "The directory that contains the sudoers configuration file", - default: lazy { platform_config_prefix } + description: "The directory that contains the sudoers configuration file.", + default: lazy { platform_config_prefix }, default_description: "Prefix values based on the node's platform" # handle legacy cookbook property def after_created diff --git a/lib/chef/resource/swap_file.rb b/lib/chef/resource/swap_file.rb index c42c7b6d59..87920e3d9b 100644 --- a/lib/chef/resource/swap_file.rb +++ b/lib/chef/resource/swap_file.rb @@ -27,7 +27,7 @@ class Chef introduced "14.0" property :path, String, - description: "The path to put the swap file on the system.", + description: "The path where the swap file will be created on the system, if it differs from the resource block name.", name_property: true property :size, Integer, diff --git a/lib/chef/resource/sysctl.rb b/lib/chef/resource/sysctl.rb index 10d6177221..643ceb233a 100644 --- a/lib/chef/resource/sysctl.rb +++ b/lib/chef/resource/sysctl.rb @@ -33,7 +33,7 @@ class Chef introduced "14.0" property :key, String, - description: "The kernel parameter key in dotted format.", + description: "The kernel parameter key in dotted format, if it differs from the resource block name.", name_property: true property :ignore_error, [TrueClass, FalseClass], diff --git a/lib/chef/resource/systemd_unit.rb b/lib/chef/resource/systemd_unit.rb index fe4d88ccd2..a7508660f7 100644 --- a/lib/chef/resource/systemd_unit.rb +++ b/lib/chef/resource/systemd_unit.rb @@ -38,10 +38,10 @@ class Chef :reload_or_try_restart # Internal provider-managed properties - property :enabled, [TrueClass, FalseClass] - property :active, [TrueClass, FalseClass] - property :masked, [TrueClass, FalseClass] - property :static, [TrueClass, FalseClass] + property :enabled, [TrueClass, FalseClass], skip_docs: true + property :active, [TrueClass, FalseClass], skip_docs: true + property :masked, [TrueClass, FalseClass], skip_docs: true + property :static, [TrueClass, FalseClass], skip_docs: true # User-provided properties property :user, String, desired_state: false diff --git a/lib/chef/resource/windows_ad_join.rb b/lib/chef/resource/windows_ad_join.rb index cb0f43e9d1..645dab5ad0 100644 --- a/lib/chef/resource/windows_ad_join.rb +++ b/lib/chef/resource/windows_ad_join.rb @@ -58,7 +58,7 @@ class Chef # define this again so we can default it to true. Otherwise failures print the password property :sensitive, [TrueClass, FalseClass], - default: true + default: true, desired_state: false action :join do description "Join the Active Directory domain." diff --git a/lib/chef/resource/windows_firewall_rule.rb b/lib/chef/resource/windows_firewall_rule.rb new file mode 100644 index 0000000000..a7e4609605 --- /dev/null +++ b/lib/chef/resource/windows_firewall_rule.rb @@ -0,0 +1,199 @@ +# Author:: Matt Clifton (spartacus003@hotmail.com) +# Author:: Matt Stratton (matt.stratton@gmail.com) +# Author:: Tor Magnus Rakvåg (tor.magnus@outlook.com) +# Author:: Tim Smith (tsmith@chef.io) +# Copyright:: 2013-2015 Matt Clifton +# Copyright:: 2018, Chef Software, Inc. +# Copyright:: 2018, Intility AS +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "chef/json_compat" + +class Chef + class Resource + class WindowsFirewallRule < Chef::Resource + resource_name :windows_firewall_rule + + description "Use the windows_firewall_rule resource to create, change or remove windows firewall rules." + introduced "14.7" + + property :rule_name, String, + name_property: true, + description: "The name to assign to the firewall rule." + + property :description, String, + default: "Firewall rule", + description: "The description to assign to the firewall rule." + + property :local_address, String, + description: "The local address the firewall rule applies to." + + property :local_port, String, + description: "The local port the firewall rule applies to." + + property :remote_address, String, + description: "The remote address the firewall rule applies to." + + property :remote_port, String, + description: "The remote port the firewall rule applies to." + + property :direction, [Symbol, String], + default: :inbound, + equal_to: [:inbound, :outbound], + description: "The direction of the firewall rule. Direction means either inbound or outbound traffic.", + coerce: proc { |d| d.is_a?(String) ? d.downcase.to_sym : d } + + property :protocol, String, + default: "TCP", + description: "The protocol the firewall rule applies to." + + property :firewall_action, [Symbol, String], + default: :allow, + equal_to: [:allow, :block, :notconfigured], + description: "The action of the firewall rule.", + coerce: proc { |f| f.is_a?(String) ? f.downcase.to_sym : f } + + property :profile, [Symbol, String], + default: :any, + equal_to: [:public, :private, :domain, :any, :notapplicable], + description: "The profile the firewall rule applies to.", + coerce: proc { |p| p.is_a?(String) ? p.downcase.to_sym : p } + + property :program, String, + description: "The program the firewall rule applies to." + + property :service, String, + description: "The service the firewall rule applies to." + + property :interface_type, [Symbol, String], + default: :any, + equal_to: [:any, :wireless, :wired, :remoteaccess], + description: "The interface type the firewall rule applies to.", + coerce: proc { |i| i.is_a?(String) ? i.downcase.to_sym : i } + + property :enabled, [TrueClass, FalseClass], + default: true, + description: "Whether or not to enable the firewall rule." + + alias_method :localip, :local_address + alias_method :remoteip, :remote_address + alias_method :localport, :local_port + alias_method :remoteport, :remote_port + alias_method :interfacetype, :interface_type + + load_current_value do + load_state_cmd = load_firewall_state(rule_name) + output = powershell_out(load_state_cmd) + if output.stdout.empty? + current_value_does_not_exist! + else + state = Chef::JSONCompat.from_json(output.stdout) + end + local_address state["local_address"] + local_port state["local_port"] + remote_address state["remote_address"] + remote_port state["remote_port"] + direction state["direction"] + protocol state["protocol"] + firewall_action state["firewall_action"] + profile state["profile"] + program state["program"] + service state["service"] + interface_type state["interface_type"] + enabled state["enabled"] + end + + action :create do + if current_resource + converge_if_changed :rule_name, :local_address, :local_port, :remote_address, :remote_port, :direction, + :protocol, :firewall_action, :profile, :program, :service, :interface_type, :enabled do + cmd = firewall_command("Set") + powershell_out!(cmd) + end + else + converge_by("create firewall rule #{new_resource.rule_name}") do + cmd = firewall_command("New") + powershell_out!(cmd) + end + end + end + + action :delete do + if current_resource + converge_by("delete firewall rule #{new_resource.rule_name}") do + powershell_out!("Remove-NetFirewallRule -Name '#{new_resource.rule_name}'") + end + else + Chef::Log.info("Firewall rule \"#{new_resource.rule_name}\" doesn't exist. Skipping.") + end + end + + action_class do + # build the command to create a firewall rule based on new_resource values + # @return [String] firewall create command + def firewall_command(cmdlet_type) + cmd = "#{cmdlet_type}-NetFirewallRule -Name '#{new_resource.rule_name}'" + cmd << " -DisplayName '#{new_resource.rule_name}'" if cmdlet_type == "New" + cmd << " -Description '#{new_resource.description}'" if new_resource.description + cmd << " -LocalAddress '#{new_resource.local_address}'" if new_resource.local_address + cmd << " -LocalPort '#{new_resource.local_port}'" if new_resource.local_port + cmd << " -RemoteAddress '#{new_resource.remote_address}'" if new_resource.remote_address + cmd << " -RemotePort '#{new_resource.remote_port}'" if new_resource.remote_port + cmd << " -Direction '#{new_resource.direction}'" if new_resource.direction + cmd << " -Protocol '#{new_resource.protocol}'" if new_resource.protocol + cmd << " -Action '#{new_resource.firewall_action}'" if new_resource.firewall_action + cmd << " -Profile '#{new_resource.profile}'" if new_resource.profile + cmd << " -Program '#{new_resource.program}'" if new_resource.program + cmd << " -Service '#{new_resource.service}'" if new_resource.service + cmd << " -InterfaceType '#{new_resource.interface_type}'" if new_resource.interface_type + cmd << " -Enabled '#{new_resource.enabled}'" + + cmd + end + end + + private + + # build the command to load the current resource + # # @return [String] current firewall state + def load_firewall_state(rule_name) + <<-EOH + $rule = Get-NetFirewallRule -Name '#{rule_name}' + $addressFilter = $rule | Get-NetFirewallAddressFilter + $portFilter = $rule | Get-NetFirewallPortFilter + $applicationFilter = $rule | Get-NetFirewallApplicationFilter + $serviceFilter = $rule | Get-NetFirewallServiceFilter + $interfaceTypeFilter = $rule | Get-NetFirewallInterfaceTypeFilter + ([PSCustomObject]@{ + rule_name = $rule.Name + description = $rule.Description + local_address = $addressFilter.LocalAddress + local_port = $portFilter.LocalPort + remote_address = $addressFilter.RemoteAddress + remote_port = $portFilter.RemotePort + direction = $rule.Direction.ToString() + protocol = $portFilter.Protocol + firewall_action = $rule.Action.ToString() + profile = $rule.Profile.ToString() + program = $applicationFilter.Program + service = $serviceFilter.Service + interface_type = $interfaceTypeFilter.InterfaceType.ToString() + enabled = [bool]::Parse($rule.Enabled.ToString()) + }) | ConvertTo-Json + EOH + end + end + end +end diff --git a/lib/chef/resource/windows_printer.rb b/lib/chef/resource/windows_printer.rb index 7d596a9691..1b9047a222 100644 --- a/lib/chef/resource/windows_printer.rb +++ b/lib/chef/resource/windows_printer.rb @@ -61,7 +61,7 @@ class Chef regex: Resolv::IPv4::Regex property :exists, [TrueClass, FalseClass], - desired_state: true + skip_docs: true PRINTERS_REG_KEY = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\\'.freeze unless defined?(PRINTERS_REG_KEY) diff --git a/lib/chef/resource/windows_printer_port.rb b/lib/chef/resource/windows_printer_port.rb index 3d54c72f47..07f0778d9b 100644 --- a/lib/chef/resource/windows_printer_port.rb +++ b/lib/chef/resource/windows_printer_port.rb @@ -56,7 +56,7 @@ class Chef default: 1, equal_to: [1, 2] property :exists, [TrueClass, FalseClass], - desired_state: true + skip_docs: true PORTS_REG_KEY = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Standard TCP/IP Port\Ports\\'.freeze unless defined?(PORTS_REG_KEY) diff --git a/lib/chef/resource/windows_service.rb b/lib/chef/resource/windows_service.rb index 1e7271b1fe..7b6593f037 100644 --- a/lib/chef/resource/windows_service.rb +++ b/lib/chef/resource/windows_service.rb @@ -50,6 +50,7 @@ class Chef # The display name to be used by user interface programs to identify the # service. This string has a maximum length of 256 characters. property :display_name, String, regex: /^.{1,256}$/, + validation_message: "The display_name can only be a maximum of 256 characters!", introduced: "14.0" # https://github.com/djberg96/win32-service/blob/ffi/lib/win32/windows/constants.rb#L19-L29 diff --git a/lib/chef/resource/windows_workgroup.rb b/lib/chef/resource/windows_workgroup.rb index 229afa2e8e..f8391a88cd 100644 --- a/lib/chef/resource/windows_workgroup.rb +++ b/lib/chef/resource/windows_workgroup.rb @@ -36,20 +36,22 @@ class Chef name_property: true property :user, String, - description: "The local administrator user to use to change the workgroup." + description: "The local administrator user to use to change the workgroup.", + desired_state: false property :password, String, - description: "The password for the local administrator user." + description: "The password for the local administrator user.", + desired_state: false property :reboot, Symbol, equal_to: [:immediate, :delayed, :never, :request_reboot, :reboot_now], validation_message: "The reboot property accepts :immediate (reboot as soon as the resource completes), :delayed (reboot once the Chef run completes), and :never (Don't reboot)", description: "Controls the system reboot behavior post workgroup joining. Reboot immediately, after the Chef run completes, or never. Note that a reboot is necessary for changes to take effect.", - default: :immediate + default: :immediate, desired_state: false # define this again so we can default it to true. Otherwise failures print the password property :sensitive, [TrueClass, FalseClass], - default: true + default: true, desired_state: false action :join do description "Update the workgroup." diff --git a/lib/chef/resource/yum_repository.rb b/lib/chef/resource/yum_repository.rb index df3bfb6454..a4b78e2ca4 100644 --- a/lib/chef/resource/yum_repository.rb +++ b/lib/chef/resource/yum_repository.rb @@ -45,7 +45,8 @@ class Chef default: true property :cost, String, regex: /^\d+$/, - description: "Relative cost of accessing this repository. Useful for weighing one repo's packages as greater/less than any other." + description: "Relative cost of accessing this repository. Useful for weighing one repo's packages as greater/less than any other.", + validation_message: "The cost property must be a numeric value!" property :description, String, description: "Descriptive name for the repository channel and maps to the 'name' parameter in a repository .conf.", @@ -95,16 +96,19 @@ class Chef description: "Number of times any attempt to retrieve a file should retry before returning an error. Setting this to '0' makes Yum try forever." property :metadata_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/, /never/], - description: "Time (in seconds) after which the metadata will expire. If the current metadata downloaded is less than the value specified, then Yum will not update the metadata against the repository. If you find that Yum is not downloading information on updates as often as you would like lower the value of this option. You can also change from the default of using seconds to using days, hours or minutes by appending a 'd', 'h' or 'm' respectively. The default is six hours to compliment yum-updates running once per hour. It is also possible to use the word ``never``, meaning that the metadata will never expire. Note: When using a metalink file, the metalink must always be newer than the metadata for the repository due to the validation, so this timeout also applies to the metalink file." + description: "Time (in seconds) after which the metadata will expire. If the current metadata downloaded is less than the value specified, then Yum will not update the metadata against the repository. If you find that Yum is not downloading information on updates as often as you would like lower the value of this option. You can also change from the default of using seconds to using days, hours or minutes by appending a 'd', 'h' or 'm' respectively. The default is six hours to compliment yum-updates running once per hour. It is also possible to use the word ``never``, meaning that the metadata will never expire. Note: When using a metalink file, the metalink must always be newer than the metadata for the repository due to the validation, so this timeout also applies to the metalink file.", + validation_message: "The metadata_expire property must be a numeric value for time in seconds, the string 'never', or a numeric value appended with with 'd', 'h', or 'm'!" property :metalink, String, description: "Specifies a URL to a metalink file for the repomd.xml, a list of mirrors for the entire repository are generated by converting the mirrors for the repomd.xml file to a baseurl." property :mirror_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/], - description: "Time (in seconds) after which the mirrorlist locally cached will expire. If the current mirrorlist is less than this many seconds old then Yum will not download another copy of the mirrorlist, it has the same extra format as metadata_expire. If you find that Yum is not downloading the mirrorlists as often as you would like lower the value of this option." + description: "Time (in seconds) after which the mirrorlist locally cached will expire. If the current mirrorlist is less than this many seconds old then Yum will not download another copy of the mirrorlist, it has the same extra format as metadata_expire. If you find that Yum is not downloading the mirrorlists as often as you would like lower the value of this option. You can also change from the default of using seconds to using days, hours or minutes by appending a 'd', 'h' or 'm' respectively.", + validation_message: "The mirror_expire property must be a numeric value for time in seconds, the string 'never', or a numeric value appended with with 'd', 'h', or 'm'!" property :mirrorlist_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/], - description: "Specifies the time (in seconds) after which the mirrorlist locally cached will expire. If the current mirrorlist is less than the value specified, then Yum will not download another copy of the mirrorlist." + description: "Specifies the time (in seconds) after which the mirrorlist locally cached will expire. If the current mirrorlist is less than the value specified, then Yum will not download another copy of the mirrorlist. You can also change from the default of using seconds to using days, hours or minutes by appending a 'd', 'h' or 'm' respectively.", + validation_message: "The mirrorlist_expire property must be a numeric value for time in seconds, the string 'never', or a numeric value appended with with 'd', 'h', or 'm'!" property :mirrorlist, String, description: "URL to a file containing a list of baseurls. This can be used instead of or with the baseurl option. Substitution variables, described below, can be used with this option." @@ -120,7 +124,8 @@ class Chef description: "Password to use with the username for basic authentication." property :priority, String, regex: /^(\d?[1-9]|[0-9][0-9])$/, - description: "Assigns a priority to a repository where the priority value is between '1' and '99' inclusive. Priorities are used to enforce ordered protection of repositories. Packages from repositories with a lower priority (higher numerical value) will never be used to upgrade packages that were installed from a repository with a higher priority (lower numerical value). The repositories with the lowest numerical priority number have the highest priority." + description: "Assigns a priority to a repository where the priority value is between '1' and '99' inclusive. Priorities are used to enforce ordered protection of repositories. Packages from repositories with a lower priority (higher numerical value) will never be used to upgrade packages that were installed from a repository with a higher priority (lower numerical value). The repositories with the lowest numerical priority number have the highest priority.", + validation_message: "The priority property must be a numeric value from 1-99!" property :proxy_password, String, description: "Password for this proxy." @@ -164,7 +169,8 @@ class Chef description: "Enable bandwidth throttling for downloads." property :timeout, String, regex: /^\d+$/, - description: "Number of seconds to wait for a connection before timing out. Defaults to 30 seconds. This may be too short of a time for extremely overloaded sites." + description: "Number of seconds to wait for a connection before timing out. Defaults to 30 seconds. This may be too short of a time for extremely overloaded sites.", + validation_message: "The timeout property must be a numeric value!" property :username, String, description: "Username to use for basic authentication to a repository." diff --git a/lib/chef/resource/zypper_repository.rb b/lib/chef/resource/zypper_repository.rb index b3e1db6b83..e4db20d446 100644 --- a/lib/chef/resource/zypper_repository.rb +++ b/lib/chef/resource/zypper_repository.rb @@ -85,7 +85,8 @@ class Chef description: "The name of the template for the repository file. Only necessary if you're not using the built in template." property :cookbook, String, - description: "The cookbook to source the repository template file from. Only necessary if you're not using the built in template." + description: "The cookbook to source the repository template file from. Only necessary if you're not using the built in template.", + desired_state: false property :gpgautoimportkeys, [TrueClass, FalseClass], description: "Automatically import the specified key when setting up the repository.", diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb index 805d278cc6..32739087d5 100644 --- a/lib/chef/resources.rb +++ b/lib/chef/resources.rb @@ -134,6 +134,7 @@ require "chef/resource/windows_certificate" require "chef/resource/windows_feature" require "chef/resource/windows_feature_dism" require "chef/resource/windows_feature_powershell" +require "chef/resource/windows_firewall_rule" require "chef/resource/windows_font" require "chef/resource/windows_pagefile" require "chef/resource/windows_path" diff --git a/lib/chef/version.rb b/lib/chef/version.rb index b2010089b8..3a1d40b5c1 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("15.0.32") + VERSION = Chef::VersionString.new("15.0.40") end # diff --git a/spec/unit/knife/osc_user_create_spec.rb b/spec/unit/knife/osc_user_create_spec.rb deleted file mode 100644 index 0413d46f78..0000000000 --- a/spec/unit/knife/osc_user_create_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-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" - -Chef::Knife::OscUserCreate.load_deps - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_create_spec.rb. - -describe Chef::Knife::OscUserCreate do - before(:each) do - @knife = Chef::Knife::OscUserCreate.new - - @stdout = StringIO.new - @stderr = StringIO.new - allow(@knife.ui).to receive(:stdout).and_return(@stdout) - allow(@knife.ui).to receive(:stderr).and_return(@stderr) - - @knife.name_args = [ "a_user" ] - @knife.config[:user_password] = "foobar" - @user = Chef::User.new - @user.name "a_user" - @user_with_private_key = Chef::User.new - @user_with_private_key.name "a_user" - @user_with_private_key.private_key "private_key" - allow(@user).to receive(:create).and_return(@user_with_private_key) - allow(Chef::User).to receive(:new).and_return(@user) - allow(Chef::User).to receive(:from_hash).and_return(@user) - allow(@knife).to receive(:edit_hash).and_return(@user.to_hash) - end - - it "creates a new user" do - expect(Chef::User).to receive(:new).and_return(@user) - expect(@user).to receive(:create) - @knife.run - expect(@stderr.string).to match /created user.+a_user/i - end - - it "sets the password" do - @knife.config[:user_password] = "a_password" - expect(@user).to receive(:password).with("a_password") - @knife.run - end - - it "exits with an error if password is blank" do - @knife.config[:user_password] = "" - expect { @knife.run }.to raise_error SystemExit - expect(@stderr.string).to match /You must specify a non-blank password/ - end - - it "sets the user name" do - expect(@user).to receive(:name).with("a_user") - @knife.run - end - - it "sets the public key if given" do - @knife.config[:user_key] = "/a/filename" - allow(File).to receive(:read).with(File.expand_path("/a/filename")).and_return("a_key") - expect(@user).to receive(:public_key).with("a_key") - @knife.run - end - - it "allows you to edit the data" do - expect(@knife).to receive(:edit_hash).with(@user) - @knife.run - end - - it "writes the private key to a file when --file is specified" do - @knife.config[:file] = "/tmp/a_file" - filehandle = double("filehandle") - expect(filehandle).to receive(:print).with("private_key") - expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle) - @knife.run - end -end diff --git a/spec/unit/knife/osc_user_delete_spec.rb b/spec/unit/knife/osc_user_delete_spec.rb deleted file mode 100644 index 6e90988156..0000000000 --- a/spec/unit/knife/osc_user_delete_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-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" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_delete_spec.rb. - -describe Chef::Knife::OscUserDelete do - before(:each) do - Chef::Knife::OscUserDelete.load_deps - @knife = Chef::Knife::OscUserDelete.new - @knife.name_args = [ "my_user" ] - end - - it "deletes the user" do - expect(@knife).to receive(:delete_object).with(Chef::User, "my_user") - @knife.run - end - - it "prints usage and exits when a user name is not provided" do - @knife.name_args = [] - expect(@knife).to receive(:show_usage) - expect(@knife.ui).to receive(:fatal) - expect { @knife.run }.to raise_error(SystemExit) - end -end diff --git a/spec/unit/knife/osc_user_edit_spec.rb b/spec/unit/knife/osc_user_edit_spec.rb deleted file mode 100644 index 1792e38027..0000000000 --- a/spec/unit/knife/osc_user_edit_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-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" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_edit_spec.rb. - -describe Chef::Knife::OscUserEdit do - before(:each) do - @stderr = StringIO.new - @stdout = StringIO.new - - Chef::Knife::OscUserEdit.load_deps - @knife = Chef::Knife::OscUserEdit.new - allow(@knife.ui).to receive(:stderr).and_return(@stderr) - allow(@knife.ui).to receive(:stdout).and_return(@stdout) - @knife.name_args = [ "my_user" ] - @knife.config[:disable_editing] = true - end - - it "loads and edits the user" do - data = { name: "my_user" } - allow(Chef::User).to receive(:load).with("my_user").and_return(data) - expect(@knife).to receive(:edit_hash).with(data).and_return(data) - @knife.run - end - - it "prints usage and exits when a user name is not provided" do - @knife.name_args = [] - expect(@knife).to receive(:show_usage) - expect(@knife.ui).to receive(:fatal) - expect { @knife.run }.to raise_error(SystemExit) - end -end diff --git a/spec/unit/knife/osc_user_list_spec.rb b/spec/unit/knife/osc_user_list_spec.rb deleted file mode 100644 index 10682eb96f..0000000000 --- a/spec/unit/knife/osc_user_list_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# Author:: Steven Danna -# Copyright:: Copyright 2012-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" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_list_spec.rb. - -describe Chef::Knife::OscUserList do - before(:each) do - Chef::Knife::OscUserList.load_deps - @knife = Chef::Knife::OscUserList.new - end - - it "lists the users" do - expect(Chef::User).to receive(:list) - expect(@knife).to receive(:format_list_for_display) - @knife.run - end -end diff --git a/spec/unit/knife/osc_user_reregister_spec.rb b/spec/unit/knife/osc_user_reregister_spec.rb deleted file mode 100644 index b0ac92568e..0000000000 --- a/spec/unit/knife/osc_user_reregister_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-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" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur in user_reregister_spec.rb. - -describe Chef::Knife::OscUserReregister do - before(:each) do - Chef::Knife::OscUserReregister.load_deps - @knife = Chef::Knife::OscUserReregister.new - @knife.name_args = [ "a_user" ] - @user_mock = double("user_mock", private_key: "private_key") - allow(Chef::User).to receive(:load).and_return(@user_mock) - @stdout = StringIO.new - allow(@knife.ui).to receive(:stdout).and_return(@stdout) - end - - it "prints usage and exits when a user name is not provided" do - @knife.name_args = [] - expect(@knife).to receive(:show_usage) - expect(@knife.ui).to receive(:fatal) - expect { @knife.run }.to raise_error(SystemExit) - end - - it "reregisters the user and prints the key" do - expect(@user_mock).to receive(:reregister).and_return(@user_mock) - @knife.run - expect(@stdout.string).to match( /private_key/ ) - end - - it "writes the private key to a file when --file is specified" do - expect(@user_mock).to receive(:reregister).and_return(@user_mock) - @knife.config[:file] = "/tmp/a_file" - filehandle = StringIO.new - expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle) - @knife.run - expect(filehandle.string).to eq("private_key") - end -end diff --git a/spec/unit/knife/osc_user_show_spec.rb b/spec/unit/knife/osc_user_show_spec.rb deleted file mode 100644 index ecdb0a9fce..0000000000 --- a/spec/unit/knife/osc_user_show_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Author:: Steven Danna (<steve@chef.io>) -# Copyright:: Copyright 2012-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" - -# DEPRECATION NOTE -# This code only remains to support users still operating with -# Open Source Chef Server 11 and should be removed once support -# for OSC 11 ends. New development should occur user_show_spec.rb. - -describe Chef::Knife::OscUserShow do - before(:each) do - Chef::Knife::OscUserShow.load_deps - @knife = Chef::Knife::OscUserShow.new - @knife.name_args = [ "my_user" ] - @user_mock = double("user_mock") - end - - it "loads and displays the user" do - expect(Chef::User).to receive(:load).with("my_user").and_return(@user_mock) - expect(@knife).to receive(:format_for_display).with(@user_mock) - @knife.run - end - - it "prints usage and exits when a user name is not provided" do - @knife.name_args = [] - expect(@knife).to receive(:show_usage) - expect(@knife.ui).to receive(:fatal) - expect { @knife.run }.to raise_error(SystemExit) - end -end diff --git a/spec/unit/knife/user_create_spec.rb b/spec/unit/knife/user_create_spec.rb index 07d72fd05a..375077abb3 100644 --- a/spec/unit/knife/user_create_spec.rb +++ b/spec/unit/knife/user_create_spec.rb @@ -38,25 +38,6 @@ describe Chef::Knife::UserCreate do allow(knife.ui).to receive(:warn) end - # delete this once OSC11 support is gone - context "when only one name_arg is passed" do - before do - knife.name_args = ["some_user"] - allow(knife).to receive(:run_osc_11_user_create).and_raise(SystemExit) - end - - it "displays the osc warning" do - expect(knife.ui).to receive(:warn).with(knife.osc_11_warning) - expect { knife.run }.to raise_error(SystemExit) - end - - it "calls knife osc_user create" do - expect(knife).to receive(:run_osc_11_user_create) - expect { knife.run }.to raise_error(SystemExit) - end - - end - context "when USERNAME isn't specified" do # from spec/support/shared/unit/knife_shared.rb it_should_behave_like "mandatory field missing" do @@ -65,17 +46,6 @@ describe Chef::Knife::UserCreate do end end - # uncomment once OSC11 support is gone, - # pending doesn't work for shared_examples_for by default - # - # context "when DISPLAY_NAME isn't specified" do - # # from spec/support/shared/unit/knife_shared.rb - # it_should_behave_like "mandatory field missing" do - # let(:name_args) { ['some_user'] } - # let(:fieldname) { 'display name' } - # end - # end - context "when FIRST_NAME isn't specified" do # from spec/support/shared/unit/knife_shared.rb it_should_behave_like "mandatory field missing" do diff --git a/spec/unit/knife/user_delete_spec.rb b/spec/unit/knife/user_delete_spec.rb index 68749fe727..b8649e2fbd 100644 --- a/spec/unit/knife/user_delete_spec.rb +++ b/spec/unit/knife/user_delete_spec.rb @@ -32,27 +32,8 @@ describe Chef::Knife::UserDelete do allow(knife.ui).to receive(:stdout).and_return(stdout) end - # delete this once OSC11 support is gone - context "when the username field is not supported by the server" do - before do - allow(knife).to receive(:run_osc_11_user_delete).and_raise(SystemExit) - allow(user).to receive(:username).and_return(nil) - end - - it "displays the osc warning" do - expect(knife.ui).to receive(:warn).with(knife.osc_11_warning) - expect { knife.run }.to raise_error(SystemExit) - end - - it "forwards the command to knife osc_user edit" do - expect(knife).to receive(:run_osc_11_user_delete) - expect { knife.run }.to raise_error(SystemExit) - end - end - it "deletes the user" do - # expect(knife).to receive(:delete_object).with(Chef::UserV1, 'my_user') - expect(knife).to receive(:delete_object).with("my_user") + expect(knife).to receive(:delete_object).with(Chef::UserV1, "my_user") knife.run end diff --git a/spec/unit/knife/user_edit_spec.rb b/spec/unit/knife/user_edit_spec.rb index 18ade54068..8ebc19de2d 100644 --- a/spec/unit/knife/user_edit_spec.rb +++ b/spec/unit/knife/user_edit_spec.rb @@ -32,24 +32,6 @@ describe Chef::Knife::UserEdit do knife.config[:disable_editing] = true end - # delete this once OSC11 support is gone - context "when the username field is not supported by the server" do - before do - allow(knife).to receive(:run_osc_11_user_edit).and_raise(SystemExit) - allow(Chef::UserV1).to receive(:load).and_return({ "username" => nil }) - end - - it "displays the osc warning" do - expect(knife.ui).to receive(:warn).with(knife.osc_11_warning) - expect { knife.run }.to raise_error(SystemExit) - end - - it "forwards the command to knife osc_user edit" do - expect(knife).to receive(:run_osc_11_user_edit) - expect { knife.run }.to raise_error(SystemExit) - end - end - it "loads and edits the user" do data = { "username" => "my_user" } allow(Chef::UserV1).to receive(:load).with("my_user").and_return(data) diff --git a/spec/unit/knife/user_reregister_spec.rb b/spec/unit/knife/user_reregister_spec.rb index 8501347087..2c861ff35d 100644 --- a/spec/unit/knife/user_reregister_spec.rb +++ b/spec/unit/knife/user_reregister_spec.rb @@ -32,24 +32,6 @@ describe Chef::Knife::UserReregister do allow(user_mock).to receive(:username).and_return("a_user") end - # delete this once OSC11 support is gone - context "when the username field is not supported by the server" do - before do - allow(knife).to receive(:run_osc_11_user_reregister).and_raise(SystemExit) - allow(user_mock).to receive(:username).and_return(nil) - end - - it "displays the osc warning" do - expect(knife.ui).to receive(:warn).with(knife.osc_11_warning) - expect { knife.run }.to raise_error(SystemExit) - end - - it "forwards the command to knife osc_user edit" do - expect(knife).to receive(:run_osc_11_user_reregister) - expect { knife.run }.to raise_error(SystemExit) - end - end - it "prints usage and exits when a user name is not provided" do knife.name_args = [] expect(knife).to receive(:show_usage) diff --git a/spec/unit/knife/user_show_spec.rb b/spec/unit/knife/user_show_spec.rb index 3a38161b34..c15dfed43c 100644 --- a/spec/unit/knife/user_show_spec.rb +++ b/spec/unit/knife/user_show_spec.rb @@ -31,25 +31,6 @@ describe Chef::Knife::UserShow do allow(knife.ui).to receive(:stdout).and_return(stdout) end - # delete this once OSC11 support is gone - context "when the username field is not supported by the server" do - before do - allow(knife).to receive(:run_osc_11_user_show).and_raise(SystemExit) - allow(Chef::UserV1).to receive(:load).with("my_user").and_return(user_mock) - allow(user_mock).to receive(:username).and_return(nil) - end - - it "displays the osc warning" do - expect(knife.ui).to receive(:warn).with(knife.osc_11_warning) - expect { knife.run }.to raise_error(SystemExit) - end - - it "forwards the command to knife osc_user edit" do - expect(knife).to receive(:run_osc_11_user_show) - expect { knife.run }.to raise_error(SystemExit) - end - end - it "loads and displays the user" do expect(Chef::UserV1).to receive(:load).with("my_user").and_return(user_mock) expect(knife).to receive(:format_for_display).with(user_mock) diff --git a/spec/unit/node/immutable_collections_spec.rb b/spec/unit/node/immutable_collections_spec.rb index 273c3d2704..2208c45717 100644 --- a/spec/unit/node/immutable_collections_spec.rb +++ b/spec/unit/node/immutable_collections_spec.rb @@ -209,7 +209,6 @@ describe Chef::Node::ImmutableArray do :merge!, :pop, :push, - :update, :reject!, :reverse!, :replace, diff --git a/spec/unit/node/vivid_mash_spec.rb b/spec/unit/node/vivid_mash_spec.rb index e1021ba0c0..cfdc813b50 100644 --- a/spec/unit/node/vivid_mash_spec.rb +++ b/spec/unit/node/vivid_mash_spec.rb @@ -1,5 +1,5 @@ # -# Copyright:: Copyright 2016, Chef Software Inc. +# Copyright:: Copyright 2016-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -351,3 +351,108 @@ describe Chef::Node::VividMash do end end end + +describe Chef::Node::AttrArray do + let(:root) { instance_double(Chef::Node::Attribute) } + + let(:array) do + Chef::Node::AttrArray.new( + %w{zero one two}, + root + ) + end + + context "#<<" do + it "converts a Hash appended with #<< to a VividMash" do + array << { "three" => "four" } + expect(array[3].class).to eql(Chef::Node::VividMash) + end + + it "deeply converts objects appended with #<<" do + array << [ { "three" => [ 0, 1] } ] + expect(array[3].class).to eql(Chef::Node::AttrArray) + expect(array[3][0].class).to eql(Chef::Node::VividMash) + expect(array[3][0]["three"].class).to eql(Chef::Node::AttrArray) + end + end + + context "#[]=" do + it "assigning a Hash into an array converts it to VividMash" do + array[0] = { "zero" => "zero2" } + expect(array[0].class).to eql(Chef::Node::VividMash) + end + end + + context "#push" do + it "pushing a Hash into an array converts it to VividMash" do + array.push({ "three" => "four" }) + expect(array[3].class).to eql(Chef::Node::VividMash) + end + end + + context "#unshift" do + it "unshifting a Hash into an array converts it to VividMash" do + array.unshift({ "zero" => "zero2" }) + expect(array[0].class).to eql(Chef::Node::VividMash) + end + end + + context "#insert" do + it "inserting a Hash into an array converts it to VividMash" do + array.insert(1, { "zero" => "zero2" }) + expect(array[1].class).to eql(Chef::Node::VividMash) + end + end + + context "#collect!" do + it "converts Hashes" do + array.collect! { |x| { "zero" => "zero2" } } + expect(array[1].class).to eql(Chef::Node::VividMash) + end + end + + context "#map!" do + it "converts Hashes" do + array.map! { |x| { "zero" => "zero2" } } + expect(array[1].class).to eql(Chef::Node::VividMash) + end + end + + context "#compact!" do + it "VividMashes remain VividMashes" do + array = Chef::Node::AttrArray.new( + [ nil, { "one" => "two" }, nil ], + root + ) + expect(array[1].class).to eql(Chef::Node::VividMash) + array.compact! + expect(array[0].class).to eql(Chef::Node::VividMash) + end + end + + context "#fill" do + it "inserts VividMashes for Hashes" do + array.fill({ "one" => "two" }) + expect(array[0].class).to eql(Chef::Node::VividMash) + end + end + + context "#flatten!" do + it "flattens sub-arrays maintaining VividMashes in them" do + array = Chef::Node::AttrArray.new( + [ [ { "one" => "two" } ], [ { "one" => "two" } ] ], + root + ) + expect(array[0][0].class).to eql(Chef::Node::VividMash) + array.flatten! + expect(array[0].class).to eql(Chef::Node::VividMash) + end + end + + context "#replace" do + it "replaces the array converting hashes to mashes" do + array.replace([ { "foo" => "bar" } ]) + expect(array[0].class).to eql(Chef::Node::VividMash) + end + end +end diff --git a/spec/unit/resource/windows_firewall_rule_spec.rb b/spec/unit/resource/windows_firewall_rule_spec.rb new file mode 100644 index 0000000000..b20425e21b --- /dev/null +++ b/spec/unit/resource/windows_firewall_rule_spec.rb @@ -0,0 +1,361 @@ +# Author:: Tor Magnus Rakvåg (tor.magnus@outlook.com) +# Copyright:: 2018, Intility AS +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" + +describe Chef::Resource::WindowsFirewallRule do + let(:resource) { Chef::Resource::WindowsFirewallRule.new("rule") } + let(:provider) { resource.provider_for_action(:enable) } + + it "has a resource name of :windows_firewall_rule" do + expect(resource.resource_name).to eql(:windows_firewall_rule) + end + + it "the name_property is 'rule_name'" do + expect(resource.rule_name).to eql("rule") + end + + it "the default action is :create" do + expect(resource.action).to eql([:create]) + end + + it "supports :create and :delete actions" do + expect { resource.action :create }.not_to raise_error + expect { resource.action :delete }.not_to raise_error + end + + it "the rule_name property accepts strings" do + resource.rule_name("rule2") + expect(resource.rule_name).to eql("rule2") + end + + it "the description property accepts strings" do + resource.description("firewall rule") + expect(resource.description).to eql("firewall rule") + end + + it "the local_address property accepts strings" do + resource.local_address("192.168.1.1") + expect(resource.local_address).to eql("192.168.1.1") + end + + it "the local_port property accepts strings" do + resource.local_port("8080") + expect(resource.local_port).to eql("8080") + end + + it "the remote_address property accepts strings" do + resource.remote_address("8.8.4.4") + expect(resource.remote_address).to eql("8.8.4.4") + end + + it "the remote_port property accepts strings" do + resource.remote_port("8081") + expect(resource.remote_port).to eql("8081") + end + + it "the direction property accepts :inbound and :outbound" do + resource.direction(:inbound) + expect(resource.direction).to eql(:inbound) + resource.direction(:outbound) + expect(resource.direction).to eql(:outbound) + end + + it "the direction property coerces strings to symbols" do + resource.direction("Inbound") + expect(resource.direction).to eql(:inbound) + end + + it "the protocol property accepts strings" do + resource.protocol("TCP") + expect(resource.protocol).to eql("TCP") + end + + it "the firewall_action property accepts :allow, :block and :notconfigured" do + resource.firewall_action(:allow) + expect(resource.firewall_action).to eql(:allow) + resource.firewall_action(:block) + expect(resource.firewall_action).to eql(:block) + resource.firewall_action(:notconfigured) + expect(resource.firewall_action).to eql(:notconfigured) + end + + it "the firewall_action property coerces strings to symbols" do + resource.firewall_action("Allow") + expect(resource.firewall_action).to eql(:allow) + end + + it "the profile property accepts :public, :private, :domain, :any and :notapplicable" do + resource.profile(:public) + expect(resource.profile).to eql(:public) + resource.profile(:private) + expect(resource.profile).to eql(:private) + resource.profile(:domain) + expect(resource.profile).to eql(:domain) + resource.profile(:any) + expect(resource.profile).to eql(:any) + resource.profile(:notapplicable) + expect(resource.profile).to eql(:notapplicable) + end + + it "the profile property coerces strings to symbols" do + resource.profile("Public") + expect(resource.profile).to eql(:public) + end + + it "the program property accepts strings" do + resource.program("C:/Test/test.exe") + expect(resource.program).to eql("C:/Test/test.exe") + end + + it "the service property accepts strings" do + resource.service("Spooler") + expect(resource.service).to eql("Spooler") + end + + it "the interface_type property accepts :any, :wireless, :wired and :remoteaccess" do + resource.interface_type(:any) + expect(resource.interface_type).to eql(:any) + resource.interface_type(:wireless) + expect(resource.interface_type).to eql(:wireless) + resource.interface_type(:wired) + expect(resource.interface_type).to eql(:wired) + resource.interface_type(:remoteaccess) + expect(resource.interface_type).to eql(:remoteaccess) + end + + it "the interface_type property coerces strings to symbols" do + resource.interface_type("Any") + expect(resource.interface_type).to eql(:any) + end + + it "the enabled property accepts true and false" do + resource.enabled(true) + expect(resource.enabled).to eql(true) + resource.enabled(false) + expect(resource.enabled).to eql(false) + end + + it "aliases :localip to :local_address" do + resource.localip("192.168.30.30") + expect(resource.local_address).to eql("192.168.30.30") + end + + it "aliases :remoteip to :remote_address" do + resource.remoteip("8.8.8.8") + expect(resource.remote_address).to eql("8.8.8.8") + end + + it "aliases :localport to :local_port" do + resource.localport("80") + expect(resource.local_port).to eql("80") + end + + it "aliases :remoteport to :remote_port" do + resource.remoteport("8080") + expect(resource.remote_port).to eql("8080") + end + + it "aliases :interfacetype to :interface_type" do + resource.interfacetype(:any) + expect(resource.interface_type).to eql(:any) + end + + describe "#firewall_command" do + before do + resource.rule_name("test_rule") + end + + context "#new" do + it "build a minimal command" do + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets a description" do + resource.description("New description") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'New description' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets LocalAddress" do + resource.local_address("127.0.0.1") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -LocalAddress '127.0.0.1' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets LocalPort" do + resource.local_port("80") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -LocalPort '80' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets RemoteAddress" do + resource.remote_address("8.8.8.8") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -RemoteAddress '8.8.8.8' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets RemotePort" do + resource.remote_port("443") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -RemotePort '443' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Direction" do + resource.direction(:outbound) + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'outbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Protocol" do + resource.protocol("UDP") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'UDP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Action" do + resource.firewall_action(:block) + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'block' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Profile" do + resource.profile(:private) + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'private' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Program" do + resource.program("C:/calc.exe") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Program 'C:/calc.exe' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Service" do + resource.service("Spooler") + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Service 'Spooler' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets InterfaceType" do + resource.interface_type(:wired) + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'wired' -Enabled 'true'") + end + + it "sets Enabled" do + resource.enabled(false) + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule' -DisplayName 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'false'") + end + + it "sets all properties" do + resource.rule_name("test_rule_the_second") + resource.description("some other rule") + resource.local_address("192.168.40.40") + resource.local_port("80") + resource.remote_address("8.8.4.4") + resource.remote_port("8081") + resource.direction(:outbound) + resource.protocol("UDP") + resource.firewall_action(:notconfigured) + resource.profile(:domain) + resource.program('%WINDIR%\System32\lsass.exe') + resource.service("SomeService") + resource.interface_type(:remoteaccess) + resource.enabled(false) + expect(provider.firewall_command("New")).to eql("New-NetFirewallRule -Name 'test_rule_the_second' -DisplayName 'test_rule_the_second' -Description 'some other rule' -LocalAddress '192.168.40.40' -LocalPort '80' -RemoteAddress '8.8.4.4' -RemotePort '8081' -Direction 'outbound' -Protocol 'UDP' -Action 'notconfigured' -Profile 'domain' -Program '%WINDIR%\\System32\\lsass.exe' -Service 'SomeService' -InterfaceType 'remoteaccess' -Enabled 'false'") + end + end + + context "#set" do + it "build a minimal command" do + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets a description" do + resource.description("New description") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'New description' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets LocalAddress" do + resource.local_address("127.0.0.1") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -LocalAddress '127.0.0.1' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets LocalPort" do + resource.local_port("80") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -LocalPort '80' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets RemoteAddress" do + resource.remote_address("8.8.8.8") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -RemoteAddress '8.8.8.8' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets RemotePort" do + resource.remote_port("443") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -RemotePort '443' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Direction" do + resource.direction(:outbound) + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'outbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Protocol" do + resource.protocol("UDP") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'UDP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Action" do + resource.firewall_action(:block) + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'block' -Profile 'any' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Profile" do + resource.profile(:private) + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'private' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Program" do + resource.program("C:/calc.exe") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Program 'C:/calc.exe' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets Service" do + resource.service("Spooler") + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -Service 'Spooler' -InterfaceType 'any' -Enabled 'true'") + end + + it "sets InterfaceType" do + resource.interface_type(:wired) + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'wired' -Enabled 'true'") + end + + it "sets Enabled" do + resource.enabled(false) + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule' -Description 'Firewall rule' -Direction 'inbound' -Protocol 'TCP' -Action 'allow' -Profile 'any' -InterfaceType 'any' -Enabled 'false'") + end + + it "sets all properties" do + resource.rule_name("test_rule_the_second") + resource.description("some other rule") + resource.local_address("192.168.40.40") + resource.local_port("80") + resource.remote_address("8.8.4.4") + resource.remote_port("8081") + resource.direction(:outbound) + resource.protocol("UDP") + resource.firewall_action(:notconfigured) + resource.profile(:domain) + resource.program('%WINDIR%\System32\lsass.exe') + resource.service("SomeService") + resource.interface_type(:remoteaccess) + resource.enabled(false) + expect(provider.firewall_command("Set")).to eql("Set-NetFirewallRule -Name 'test_rule_the_second' -Description 'some other rule' -LocalAddress '192.168.40.40' -LocalPort '80' -RemoteAddress '8.8.4.4' -RemotePort '8081' -Direction 'outbound' -Protocol 'UDP' -Action 'notconfigured' -Profile 'domain' -Program '%WINDIR%\\System32\\lsass.exe' -Service 'SomeService' -InterfaceType 'remoteaccess' -Enabled 'false'") + end + end + end +end |