chef 14.6.47 → 14.7.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/chef-universal-mingw32.gemspec +1 -0
  3. data/lib/chef/application/apply.rb +6 -4
  4. data/lib/chef/knife/config_list_profiles.rb +1 -1
  5. data/lib/chef/knife/list.rb +1 -1
  6. data/lib/chef/knife/raw.rb +1 -1
  7. data/lib/chef/knife/role_env_run_list_clear.rb +1 -1
  8. data/lib/chef/knife/role_env_run_list_remove.rb +1 -1
  9. data/lib/chef/knife/role_env_run_list_replace.rb +1 -1
  10. data/lib/chef/knife/role_env_run_list_set.rb +1 -1
  11. data/lib/chef/knife/role_run_list_clear.rb +1 -1
  12. data/lib/chef/knife/role_run_list_remove.rb +1 -1
  13. data/lib/chef/knife/role_run_list_replace.rb +1 -1
  14. data/lib/chef/knife/role_run_list_set.rb +1 -1
  15. data/lib/chef/knife/show.rb +1 -1
  16. data/lib/chef/knife/upload.rb +1 -1
  17. data/lib/chef/knife/xargs.rb +1 -1
  18. data/lib/chef/node/attribute.rb +189 -185
  19. data/lib/chef/platform/rebooter.rb +1 -0
  20. data/lib/chef/property.rb +25 -1
  21. data/lib/chef/provider/windows_task.rb +19 -6
  22. data/lib/chef/resource.rb +17 -2
  23. data/lib/chef/resource/apt_preference.rb +2 -1
  24. data/lib/chef/resource/apt_repository.rb +1 -1
  25. data/lib/chef/resource/apt_update.rb +1 -0
  26. data/lib/chef/resource/build_essential.rb +1 -1
  27. data/lib/chef/resource/cab_package.rb +1 -1
  28. data/lib/chef/resource/chef_gem.rb +1 -1
  29. data/lib/chef/resource/cookbook_file.rb +2 -1
  30. data/lib/chef/resource/cron_d.rb +1 -1
  31. data/lib/chef/resource/dmg_package.rb +52 -40
  32. data/lib/chef/resource/execute.rb +2 -2
  33. data/lib/chef/resource/file.rb +1 -1
  34. data/lib/chef/resource/group.rb +2 -2
  35. data/lib/chef/resource/homebrew_cask.rb +3 -2
  36. data/lib/chef/resource/homebrew_tap.rb +2 -2
  37. data/lib/chef/resource/hostname.rb +2 -2
  38. data/lib/chef/resource/kernel_module.rb +19 -13
  39. data/lib/chef/resource/locale.rb +1 -0
  40. data/lib/chef/resource/macos_userdefaults.rb +7 -6
  41. data/lib/chef/resource/mdadm.rb +3 -2
  42. data/lib/chef/resource/mount.rb +3 -3
  43. data/lib/chef/resource/openssl_dhparam.rb +1 -1
  44. data/lib/chef/resource/openssl_ec_private_key.rb +1 -1
  45. data/lib/chef/resource/openssl_ec_public_key.rb +3 -3
  46. data/lib/chef/resource/openssl_rsa_private_key.rb +2 -2
  47. data/lib/chef/resource/openssl_rsa_public_key.rb +3 -3
  48. data/lib/chef/resource/openssl_x509_certificate.rb +1 -1
  49. data/lib/chef/resource/openssl_x509_crl.rb +1 -1
  50. data/lib/chef/resource/openssl_x509_request.rb +1 -1
  51. data/lib/chef/resource/package.rb +1 -1
  52. data/lib/chef/resource/powershell_package.rb +1 -1
  53. data/lib/chef/resource/remote_directory.rb +2 -2
  54. data/lib/chef/resource/rhsm_errata.rb +1 -1
  55. data/lib/chef/resource/rhsm_errata_level.rb +1 -1
  56. data/lib/chef/resource/rhsm_register.rb +7 -7
  57. data/lib/chef/resource/rhsm_repo.rb +1 -1
  58. data/lib/chef/resource/rhsm_subscription.rb +1 -1
  59. data/lib/chef/resource/sudo.rb +8 -8
  60. data/lib/chef/resource/swap_file.rb +1 -1
  61. data/lib/chef/resource/sysctl.rb +2 -2
  62. data/lib/chef/resource/systemd_unit.rb +19 -11
  63. data/lib/chef/resource/timezone.rb +60 -32
  64. data/lib/chef/resource/windows_ad_join.rb +1 -1
  65. data/lib/chef/resource/windows_auto_run.rb +1 -1
  66. data/lib/chef/resource/windows_certificate.rb +269 -0
  67. data/lib/chef/resource/windows_env.rb +12 -3
  68. data/lib/chef/resource/windows_feature.rb +6 -11
  69. data/lib/chef/resource/windows_feature_dism.rb +2 -2
  70. data/lib/chef/resource/windows_feature_powershell.rb +5 -9
  71. data/lib/chef/resource/windows_firewall_rule.rb +205 -0
  72. data/lib/chef/resource/windows_path.rb +3 -1
  73. data/lib/chef/resource/windows_printer.rb +2 -2
  74. data/lib/chef/resource/windows_printer_port.rb +3 -3
  75. data/lib/chef/resource/windows_service.rb +1 -0
  76. data/lib/chef/resource/windows_share.rb +315 -0
  77. data/lib/chef/resource/windows_task.rb +4 -0
  78. data/lib/chef/resource/windows_workgroup.rb +6 -4
  79. data/lib/chef/resource/yum_repository.rb +13 -7
  80. data/lib/chef/resource/zypper_package.rb +2 -2
  81. data/lib/chef/resource/zypper_repository.rb +2 -1
  82. data/lib/chef/resource_inspector.rb +4 -4
  83. data/lib/chef/resources.rb +3 -0
  84. data/lib/chef/version.rb +1 -1
  85. data/spec/functional/resource/windows_task_spec.rb +39 -0
  86. data/spec/support/platform_helpers.rb +2 -1
  87. data/spec/unit/resource/windows_certificate.rb +46 -0
  88. data/spec/unit/resource/windows_firewall_rule_spec.rb +401 -0
  89. data/spec/unit/resource/windows_share.rb +39 -0
  90. metadata +10 -4
@@ -116,6 +116,10 @@ class Chef
116
116
  introduced: "14.4", default: false,
117
117
  description: "Scheduled task option when system is switching on battery."
118
118
 
119
+ property :description, String,
120
+ introduced: "14.7",
121
+ description: "The task description."
122
+
119
123
  attr_accessor :exists, :task, :command_arguments
120
124
 
121
125
  VALID_WEEK_DAYS = %w{ mon tue wed thu fri sat sun * }.freeze
@@ -36,20 +36,22 @@ class Chef
36
36
  name_property: true
37
37
 
38
38
  property :user, String,
39
- description: "The local administrator user to use to change the workgroup."
39
+ description: "The local administrator user to use to change the workgroup.",
40
+ desired_state: false
40
41
 
41
42
  property :password, String,
42
- description: "The password for the local administrator user."
43
+ description: "The password for the local administrator user.",
44
+ desired_state: false
43
45
 
44
46
  property :reboot, Symbol,
45
47
  equal_to: [:immediate, :delayed, :never, :request_reboot, :reboot_now],
46
48
  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)",
47
49
  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.",
48
- default: :immediate
50
+ default: :immediate, desired_state: false
49
51
 
50
52
  # define this again so we can default it to true. Otherwise failures print the password
51
53
  property :sensitive, [TrueClass, FalseClass],
52
- default: true
54
+ default: true, desired_state: false
53
55
 
54
56
  action :join do
55
57
  description "Update the workgroup."
@@ -45,7 +45,8 @@ class Chef
45
45
  default: true
46
46
 
47
47
  property :cost, String, regex: /^\d+$/,
48
- description: "Relative cost of accessing this repository. Useful for weighing one repo's packages as greater/less than any other."
48
+ description: "Relative cost of accessing this repository. Useful for weighing one repo's packages as greater/less than any other.",
49
+ validation_message: "The cost property must be a numeric value!"
49
50
 
50
51
  property :description, String,
51
52
  description: "Descriptive name for the repository channel and maps to the 'name' parameter in a repository .conf.",
@@ -73,7 +74,7 @@ class Chef
73
74
  default: true
74
75
 
75
76
  property :gpgkey, [String, Array],
76
- description: "URL pointing to the ASCII-armored GPG key file for the repository. This is used if Yum needs a public key to verify a package and the required key hasn't been imported into the RPM database. If this option is set, Yum will automatically import the key from the specified URL. Multiple URLs may be specified in the same manner as the baseurl option. If a GPG key is required to install a package from a repository, all keys specified for that repository will be installed."
77
+ description: "URL pointing to the ASCII-armored GPG key file for the repository. This is used if Yum needs a public key to verify a package and the required key hasn't been imported into the RPM database. If this option is set, Yum will automatically import the key from the specified URL. Multiple URLs may be specified in the same manner as the baseurl option. If a GPG key is required to install a package from a repository, all keys specified for that repository will be installed.\nMultiple URLs may be specified in the same manner as the baseurl option. If a GPG key is required to install a package from a repository, all keys specified for that repository will be installed."
77
78
 
78
79
  property :http_caching, String, equal_to: %w{packages all none},
79
80
  description: "Determines how upstream HTTP caches are instructed to handle any HTTP downloads that Yum does. This option can take the following values: all (all HTTP downloads should be cached), packages (only RPM package downloads should be cached, but not repository metadata downloads), or none (no HTTP downloads should be cached)"
@@ -95,16 +96,19 @@ class Chef
95
96
  description: "Number of times any attempt to retrieve a file should retry before returning an error. Setting this to '0' makes Yum try forever."
96
97
 
97
98
  property :metadata_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/, /never/],
98
- 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."
99
+ 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.",
100
+ 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'!"
99
101
 
100
102
  property :metalink, String,
101
103
  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."
102
104
 
103
105
  property :mirror_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/],
104
- 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."
106
+ 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.",
107
+ 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'!"
105
108
 
106
109
  property :mirrorlist_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/],
107
- 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."
110
+ 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.",
111
+ 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'!"
108
112
 
109
113
  property :mirrorlist, String,
110
114
  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
120
124
  description: "Password to use with the username for basic authentication."
121
125
 
122
126
  property :priority, String, regex: /^(\d?[1-9]|[0-9][0-9])$/,
123
- 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."
127
+ 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.",
128
+ validation_message: "The priority property must be a numeric value from 1-99!"
124
129
 
125
130
  property :proxy_password, String,
126
131
  description: "Password for this proxy."
@@ -164,7 +169,8 @@ class Chef
164
169
  description: "Enable bandwidth throttling for downloads."
165
170
 
166
171
  property :timeout, String, regex: /^\d+$/,
167
- 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."
172
+ 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.",
173
+ validation_message: "The timeout property must be a numeric value!"
168
174
 
169
175
  property :username, String,
170
176
  description: "Username to use for basic authentication to a repository."
@@ -29,14 +29,14 @@ class Chef
29
29
 
30
30
  property :gpg_check, [ TrueClass, FalseClass ],
31
31
  description: "Verify the package's GPG signature. Can also be controlled site-wide using the ``zypper_check_gpg`` config option.",
32
- default: lazy { Chef::Config[:zypper_check_gpg] }
32
+ default: lazy { Chef::Config[:zypper_check_gpg] }, default_description: "true"
33
33
 
34
34
  property :allow_downgrade, [ TrueClass, FalseClass ],
35
35
  description: "Allow downgrading a package to satisfy requested version requirements.",
36
36
  default: false, introduced: "13.6"
37
37
 
38
38
  property :global_options, [ String, Array ],
39
- description: "One (or more) additional options that are passed to the package resource other than options to the command.",
39
+ description: "One (or more) additional command options that are passed to the command. For example, common zypper directives, such as '--no-recommends'. See the zypper man page at https://en.opensuse.org/SDB:Zypper_manual_(plain) for the full list.",
40
40
  coerce: proc { |x| x.is_a?(String) ? x.shellsplit : x },
41
41
  introduced: "14.6"
42
42
  end
@@ -85,7 +85,8 @@ class Chef
85
85
  description: "The name of the template for the repository file. Only necessary if you're not using the built in template."
86
86
 
87
87
  property :cookbook, String,
88
- description: "The cookbook to source the repository template file from. Only necessary if you're not using the built in template."
88
+ description: "The cookbook to source the repository template file from. Only necessary if you're not using the built in template.",
89
+ desired_state: false
89
90
 
90
91
  property :gpgautoimportkeys, [TrueClass, FalseClass],
91
92
  description: "Automatically import the specified key when setting up the repository.",
@@ -31,7 +31,7 @@ module ResourceInspector
31
31
  # code for the resource ourselves and just no
32
32
  "lazy default"
33
33
  else
34
- default
34
+ default.is_a?(Symbol) ? default.inspect : default # inspect properly returns symbols
35
35
  end
36
36
  end
37
37
 
@@ -46,9 +46,9 @@ module ResourceInspector
46
46
  data[:preview] = resource.preview_resource
47
47
 
48
48
  properties = unless complete
49
- resource.properties.reject { |_, k| k.options[:declared_in] == Chef::Resource }
49
+ resource.properties.reject { |_, k| k.options[:declared_in] == Chef::Resource || k.options[:skip_docs] }
50
50
  else
51
- resource.properties
51
+ resource.properties.reject { |_, k| k.options[:skip_docs] }
52
52
  end
53
53
 
54
54
  data[:properties] = properties.each_with_object([]) do |(n, k), acc|
@@ -57,7 +57,7 @@ module ResourceInspector
57
57
  introduced: opts[:introduced], is: opts[:is],
58
58
  deprecated: opts[:deprecated] || false,
59
59
  required: opts[:required] || false,
60
- default: get_default(opts[:default]),
60
+ default: opts[:default_description] || get_default(opts[:default]),
61
61
  name_property: opts[:name_property] || false }
62
62
  end
63
63
  data
@@ -130,14 +130,17 @@ require "chef/resource/powershell_package"
130
130
  require "chef/resource/msu_package"
131
131
  require "chef/resource/windows_ad_join"
132
132
  require "chef/resource/windows_auto_run"
133
+ require "chef/resource/windows_certificate"
133
134
  require "chef/resource/windows_feature"
134
135
  require "chef/resource/windows_feature_dism"
135
136
  require "chef/resource/windows_feature_powershell"
137
+ require "chef/resource/windows_firewall_rule"
136
138
  require "chef/resource/windows_font"
137
139
  require "chef/resource/windows_pagefile"
138
140
  require "chef/resource/windows_path"
139
141
  require "chef/resource/windows_printer"
140
142
  require "chef/resource/windows_printer_port"
143
+ require "chef/resource/windows_share"
141
144
  require "chef/resource/windows_shortcut"
142
145
  require "chef/resource/windows_task"
143
146
  require "chef/resource/windows_workgroup"
@@ -23,7 +23,7 @@ require "chef/version_string"
23
23
 
24
24
  class Chef
25
25
  CHEF_ROOT = File.expand_path("../..", __FILE__)
26
- VERSION = Chef::VersionString.new("14.6.47")
26
+ VERSION = Chef::VersionString.new("14.7.17")
27
27
  end
28
28
 
29
29
  #
@@ -132,6 +132,45 @@ describe Chef::Resource::WindowsTask, :windows_only do
132
132
  end
133
133
  end
134
134
 
135
+ context "when description is passed" do
136
+ subject do
137
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
138
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
139
+ new_resource.command task_name
140
+ # Make sure MM/DD/YYYY is accepted
141
+ new_resource.start_day "09/20/2017"
142
+ new_resource.frequency :hourly
143
+ new_resource
144
+ end
145
+
146
+ let(:some_description) { "this is test description" }
147
+
148
+ it "create the task and sets its description" do
149
+ subject.description some_description
150
+ call_for_create_action
151
+ # loading current resource again to check new task is creted and it matches task parameters
152
+ current_resource = call_for_load_current_resource
153
+ expect(current_resource.exists).to eq(true)
154
+ expect(current_resource.task.description).to eq(some_description)
155
+ end
156
+
157
+ it "does not converge the resource if it is already converged" do
158
+ subject.description some_description
159
+ subject.run_action(:create)
160
+ subject.description some_description
161
+ subject.run_action(:create)
162
+ expect(subject).not_to be_updated_by_last_action
163
+ end
164
+
165
+ it "updates task with new description if task already exist" do
166
+ subject.description some_description
167
+ subject.run_action(:create)
168
+ subject.description "test description"
169
+ subject.run_action(:create)
170
+ expect(subject).to be_updated_by_last_action
171
+ end
172
+ end
173
+
135
174
  context "when frequency_modifier are not passed" do
136
175
  subject do
137
176
  new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
@@ -220,7 +220,8 @@ def selinux_enabled?
220
220
  end
221
221
 
222
222
  def suse?
223
- File.exists?("/etc/SuSE-release")
223
+ ::File.exists?("/etc/SuSE-release") ||
224
+ ( ::File.exists?("/etc/os-release") && /sles|suse/.match?(File.read("/etc/os-release")) )
224
225
  end
225
226
 
226
227
  def root?
@@ -0,0 +1,46 @@
1
+ #
2
+ # Copyright:: Copyright 2018, Chef Software, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+
20
+ describe Chef::Resource::WindowsCertificate do
21
+ let(:resource) { Chef::Resource::WindowsCertificate.new("foobar") }
22
+
23
+ it "sets resource name as :windows_certificate" do
24
+ expect(resource.resource_name).to eql(:windows_certificate)
25
+ end
26
+
27
+ it "the source property is the name_property" do
28
+ expect(resource.source).to eql("foobar")
29
+ end
30
+
31
+ it "sets the default action as :create" do
32
+ expect(resource.action).to eql([:create])
33
+ end
34
+
35
+ it "supports :create, :acl_add, :delete, and :verify actions" do
36
+ expect { resource.action :create }.not_to raise_error
37
+ expect { resource.action :acl_add }.not_to raise_error
38
+ expect { resource.action :delete }.not_to raise_error
39
+ expect { resource.action :verify }.not_to raise_error
40
+ end
41
+
42
+ it "sets sensitive to true if the pfx_password property is set" do
43
+ resource.pfx_password "foo"
44
+ expect(resource.sensitive).to be_truthy
45
+ end
46
+ end
@@ -0,0 +1,401 @@
1
+ # Author:: Tor Magnus Rakvåg (tor.magnus@outlook.com)
2
+ # Copyright:: 2018, Intility AS
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+
20
+ describe Chef::Resource::WindowsFirewallRule do
21
+ let(:resource) { Chef::Resource::WindowsFirewallRule.new("rule") }
22
+ let(:provider) { resource.provider_for_action(:enable) }
23
+
24
+ it "has a resource name of :windows_firewall_rule" do
25
+ expect(resource.resource_name).to eql(:windows_firewall_rule)
26
+ end
27
+
28
+ it "the name_property is 'rule_name'" do
29
+ expect(resource.rule_name).to eql("rule")
30
+ end
31
+
32
+ it "the default action is :create" do
33
+ expect(resource.action).to eql([:create])
34
+ end
35
+
36
+ it "supports :create and :delete actions" do
37
+ expect { resource.action :create }.not_to raise_error
38
+ expect { resource.action :delete }.not_to raise_error
39
+ end
40
+
41
+ it "the rule_name property accepts strings" do
42
+ resource.rule_name("rule2")
43
+ expect(resource.rule_name).to eql("rule2")
44
+ end
45
+
46
+ it "the description property accepts strings" do
47
+ resource.description("firewall rule")
48
+ expect(resource.description).to eql("firewall rule")
49
+ end
50
+
51
+ it "the local_address property accepts strings" do
52
+ resource.local_address("192.168.1.1")
53
+ expect(resource.local_address).to eql("192.168.1.1")
54
+ end
55
+
56
+ it "the local_port property accepts integers" do
57
+ resource.local_port(8080)
58
+ expect(resource.local_port).to eql(["8080"])
59
+ end
60
+
61
+ it "the local_port property accepts strings" do
62
+ resource.local_port("8080")
63
+ expect(resource.local_port).to eql(["8080"])
64
+ end
65
+
66
+ it "the local_port property accepts comma separated lists without spaces" do
67
+ resource.local_port("8080,8081")
68
+ expect(resource.local_port).to eql(%w{8080 8081})
69
+ end
70
+
71
+ it "the local_port property accepts comma separated lists with spaces" do
72
+ resource.local_port("8080, 8081")
73
+ expect(resource.local_port).to eql(%w{8080 8081})
74
+ end
75
+
76
+ it "the local_port property accepts arrays and coerces to a sorta array of strings" do
77
+ resource.local_port([8081, 8080])
78
+ expect(resource.local_port).to eql(%w{8080 8081})
79
+ end
80
+
81
+ it "the remote_address property accepts strings" do
82
+ resource.remote_address("8.8.4.4")
83
+ expect(resource.remote_address).to eql("8.8.4.4")
84
+ end
85
+
86
+ it "the remote_port property accepts strings" do
87
+ resource.remote_port("8081")
88
+ expect(resource.remote_port).to eql(["8081"])
89
+ end
90
+
91
+ it "the remote_port property accepts integers" do
92
+ resource.remote_port(8081)
93
+ expect(resource.remote_port).to eql(["8081"])
94
+ end
95
+
96
+ it "the remote_port property accepts comma separated lists without spaces" do
97
+ resource.remote_port("8080,8081")
98
+ expect(resource.remote_port).to eql(%w{8080 8081})
99
+ end
100
+
101
+ it "the remote_port property accepts comma separated lists with spaces" do
102
+ resource.remote_port("8080, 8081")
103
+ expect(resource.remote_port).to eql(%w{8080 8081})
104
+ end
105
+
106
+ it "the remote_port property accepts arrays and coerces to a sorta array of strings" do
107
+ resource.remote_port([8081, 8080])
108
+ expect(resource.remote_port).to eql(%w{8080 8081})
109
+ end
110
+
111
+ it "the direction property accepts :inbound and :outbound" do
112
+ resource.direction(:inbound)
113
+ expect(resource.direction).to eql(:inbound)
114
+ resource.direction(:outbound)
115
+ expect(resource.direction).to eql(:outbound)
116
+ end
117
+
118
+ it "the direction property coerces strings to symbols" do
119
+ resource.direction("Inbound")
120
+ expect(resource.direction).to eql(:inbound)
121
+ end
122
+
123
+ it "the protocol property accepts strings" do
124
+ resource.protocol("TCP")
125
+ expect(resource.protocol).to eql("TCP")
126
+ end
127
+
128
+ it "the firewall_action property accepts :allow, :block and :notconfigured" do
129
+ resource.firewall_action(:allow)
130
+ expect(resource.firewall_action).to eql(:allow)
131
+ resource.firewall_action(:block)
132
+ expect(resource.firewall_action).to eql(:block)
133
+ resource.firewall_action(:notconfigured)
134
+ expect(resource.firewall_action).to eql(:notconfigured)
135
+ end
136
+
137
+ it "the firewall_action property coerces strings to symbols" do
138
+ resource.firewall_action("Allow")
139
+ expect(resource.firewall_action).to eql(:allow)
140
+ end
141
+
142
+ it "the profile property accepts :public, :private, :domain, :any and :notapplicable" do
143
+ resource.profile(:public)
144
+ expect(resource.profile).to eql(:public)
145
+ resource.profile(:private)
146
+ expect(resource.profile).to eql(:private)
147
+ resource.profile(:domain)
148
+ expect(resource.profile).to eql(:domain)
149
+ resource.profile(:any)
150
+ expect(resource.profile).to eql(:any)
151
+ resource.profile(:notapplicable)
152
+ expect(resource.profile).to eql(:notapplicable)
153
+ end
154
+
155
+ it "the profile property coerces strings to symbols" do
156
+ resource.profile("Public")
157
+ expect(resource.profile).to eql(:public)
158
+ end
159
+
160
+ it "the program property accepts strings" do
161
+ resource.program("C:/Test/test.exe")
162
+ expect(resource.program).to eql("C:/Test/test.exe")
163
+ end
164
+
165
+ it "the service property accepts strings" do
166
+ resource.service("Spooler")
167
+ expect(resource.service).to eql("Spooler")
168
+ end
169
+
170
+ it "the interface_type property accepts :any, :wireless, :wired and :remoteaccess" do
171
+ resource.interface_type(:any)
172
+ expect(resource.interface_type).to eql(:any)
173
+ resource.interface_type(:wireless)
174
+ expect(resource.interface_type).to eql(:wireless)
175
+ resource.interface_type(:wired)
176
+ expect(resource.interface_type).to eql(:wired)
177
+ resource.interface_type(:remoteaccess)
178
+ expect(resource.interface_type).to eql(:remoteaccess)
179
+ end
180
+
181
+ it "the interface_type property coerces strings to symbols" do
182
+ resource.interface_type("Any")
183
+ expect(resource.interface_type).to eql(:any)
184
+ end
185
+
186
+ it "the enabled property accepts true and false" do
187
+ resource.enabled(true)
188
+ expect(resource.enabled).to eql(true)
189
+ resource.enabled(false)
190
+ expect(resource.enabled).to eql(false)
191
+ end
192
+
193
+ it "aliases :localip to :local_address" do
194
+ resource.localip("192.168.30.30")
195
+ expect(resource.local_address).to eql("192.168.30.30")
196
+ end
197
+
198
+ it "aliases :remoteip to :remote_address" do
199
+ resource.remoteip("8.8.8.8")
200
+ expect(resource.remote_address).to eql("8.8.8.8")
201
+ end
202
+
203
+ it "aliases :localport to :local_port" do
204
+ resource.localport("80")
205
+ expect(resource.local_port).to eql(["80"])
206
+ end
207
+
208
+ it "aliases :remoteport to :remote_port" do
209
+ resource.remoteport("8080")
210
+ expect(resource.remote_port).to eql(["8080"])
211
+ end
212
+
213
+ it "aliases :interfacetype to :interface_type" do
214
+ resource.interfacetype(:any)
215
+ expect(resource.interface_type).to eql(:any)
216
+ end
217
+
218
+ describe "#firewall_command" do
219
+ before do
220
+ resource.rule_name("test_rule")
221
+ end
222
+
223
+ context "#new" do
224
+ it "build a minimal command" do
225
+ 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'")
226
+ end
227
+
228
+ it "sets a description" do
229
+ resource.description("New description")
230
+ 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'")
231
+ end
232
+
233
+ it "sets LocalAddress" do
234
+ resource.local_address("127.0.0.1")
235
+ 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'")
236
+ end
237
+
238
+ it "sets LocalPort" do
239
+ resource.local_port("80")
240
+ 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'")
241
+ end
242
+
243
+ it "sets RemoteAddress" do
244
+ resource.remote_address("8.8.8.8")
245
+ 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'")
246
+ end
247
+
248
+ it "sets RemotePort" do
249
+ resource.remote_port("443")
250
+ 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'")
251
+ end
252
+
253
+ it "sets Direction" do
254
+ resource.direction(:outbound)
255
+ 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'")
256
+ end
257
+
258
+ it "sets Protocol" do
259
+ resource.protocol("UDP")
260
+ 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'")
261
+ end
262
+
263
+ it "sets Action" do
264
+ resource.firewall_action(:block)
265
+ 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'")
266
+ end
267
+
268
+ it "sets Profile" do
269
+ resource.profile(:private)
270
+ 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'")
271
+ end
272
+
273
+ it "sets Program" do
274
+ resource.program("C:/calc.exe")
275
+ 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'")
276
+ end
277
+
278
+ it "sets Service" do
279
+ resource.service("Spooler")
280
+ 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'")
281
+ end
282
+
283
+ it "sets InterfaceType" do
284
+ resource.interface_type(:wired)
285
+ 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'")
286
+ end
287
+
288
+ it "sets Enabled" do
289
+ resource.enabled(false)
290
+ 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'")
291
+ end
292
+
293
+ it "sets all properties" do
294
+ resource.rule_name("test_rule_the_second")
295
+ resource.description("some other rule")
296
+ resource.local_address("192.168.40.40")
297
+ resource.local_port("80")
298
+ resource.remote_address("8.8.4.4")
299
+ resource.remote_port("8081")
300
+ resource.direction(:outbound)
301
+ resource.protocol("UDP")
302
+ resource.firewall_action(:notconfigured)
303
+ resource.profile(:domain)
304
+ resource.program('%WINDIR%\System32\lsass.exe')
305
+ resource.service("SomeService")
306
+ resource.interface_type(:remoteaccess)
307
+ resource.enabled(false)
308
+ 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'")
309
+ end
310
+ end
311
+
312
+ context "#set" do
313
+ it "build a minimal command" do
314
+ 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'")
315
+ end
316
+
317
+ it "sets a description" do
318
+ resource.description("New description")
319
+ 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'")
320
+ end
321
+
322
+ it "sets LocalAddress" do
323
+ resource.local_address("127.0.0.1")
324
+ 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'")
325
+ end
326
+
327
+ it "sets LocalPort" do
328
+ resource.local_port("80")
329
+ 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'")
330
+ end
331
+
332
+ it "sets RemoteAddress" do
333
+ resource.remote_address("8.8.8.8")
334
+ 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'")
335
+ end
336
+
337
+ it "sets RemotePort" do
338
+ resource.remote_port("443")
339
+ 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'")
340
+ end
341
+
342
+ it "sets Direction" do
343
+ resource.direction(:outbound)
344
+ 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'")
345
+ end
346
+
347
+ it "sets Protocol" do
348
+ resource.protocol("UDP")
349
+ 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'")
350
+ end
351
+
352
+ it "sets Action" do
353
+ resource.firewall_action(:block)
354
+ 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'")
355
+ end
356
+
357
+ it "sets Profile" do
358
+ resource.profile(:private)
359
+ 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'")
360
+ end
361
+
362
+ it "sets Program" do
363
+ resource.program("C:/calc.exe")
364
+ 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'")
365
+ end
366
+
367
+ it "sets Service" do
368
+ resource.service("Spooler")
369
+ 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'")
370
+ end
371
+
372
+ it "sets InterfaceType" do
373
+ resource.interface_type(:wired)
374
+ 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'")
375
+ end
376
+
377
+ it "sets Enabled" do
378
+ resource.enabled(false)
379
+ 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'")
380
+ end
381
+
382
+ it "sets all properties" do
383
+ resource.rule_name("test_rule_the_second")
384
+ resource.description("some other rule")
385
+ resource.local_address("192.168.40.40")
386
+ resource.local_port("80")
387
+ resource.remote_address("8.8.4.4")
388
+ resource.remote_port("8081")
389
+ resource.direction(:outbound)
390
+ resource.protocol("UDP")
391
+ resource.firewall_action(:notconfigured)
392
+ resource.profile(:domain)
393
+ resource.program('%WINDIR%\System32\lsass.exe')
394
+ resource.service("SomeService")
395
+ resource.interface_type(:remoteaccess)
396
+ resource.enabled(false)
397
+ 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'")
398
+ end
399
+ end
400
+ end
401
+ end