chef 17.0.242 → 17.1.35

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -12
  3. data/Rakefile +2 -2
  4. data/chef.gemspec +9 -20
  5. data/lib/chef/chef_fs/file_pattern.rb +2 -2
  6. data/lib/chef/compliance/default_attributes.rb +1 -1
  7. data/lib/chef/compliance/reporter/automate.rb +1 -1
  8. data/lib/chef/compliance/runner.rb +2 -2
  9. data/lib/chef/cookbook/cookbook_version_loader.rb +3 -3
  10. data/lib/chef/cookbook/gem_installer.rb +5 -1
  11. data/lib/chef/dsl/declare_resource.rb +5 -10
  12. data/lib/chef/formatters/doc.rb +2 -1
  13. data/lib/chef/node.rb +1 -1
  14. data/lib/chef/provider/directory.rb +6 -6
  15. data/lib/chef/provider/link.rb +1 -1
  16. data/lib/chef/provider/package/dnf/dnf_helper.py +11 -10
  17. data/lib/chef/provider/package/dnf/python_helper.rb +9 -8
  18. data/lib/chef/provider/package/yum.rb +1 -4
  19. data/lib/chef/provider/package/yum/python_helper.rb +15 -10
  20. data/lib/chef/provider/package/yum/yum_helper.py +46 -62
  21. data/lib/chef/provider/registry_key.rb +1 -1
  22. data/lib/chef/provider/service/systemd.rb +1 -1
  23. data/lib/chef/provider/systemd_unit.rb +1 -1
  24. data/lib/chef/provider/template/content.rb +1 -1
  25. data/lib/chef/provider/windows_script.rb +1 -1
  26. data/lib/chef/resource.rb +6 -7
  27. data/lib/chef/resource/execute.rb +2 -2
  28. data/lib/chef/resource/inspec_waiver_file_entry.rb +155 -0
  29. data/lib/chef/resource/lwrp_base.rb +17 -2
  30. data/lib/chef/resource/remote_file.rb +2 -2
  31. data/lib/chef/resource/windows_env.rb +1 -1
  32. data/lib/chef/resource/windows_font.rb +1 -1
  33. data/lib/chef/resource/windows_pagefile.rb +2 -2
  34. data/lib/chef/resource/windows_path.rb +2 -2
  35. data/lib/chef/resource/windows_security_policy.rb +5 -2
  36. data/lib/chef/resource/windows_task.rb +1 -1
  37. data/lib/chef/resource_builder.rb +8 -2
  38. data/lib/chef/resources.rb +1 -0
  39. data/lib/chef/run_lock.rb +1 -1
  40. data/lib/chef/runner.rb +1 -1
  41. data/lib/chef/shell/ext.rb +3 -3
  42. data/lib/chef/version.rb +1 -1
  43. data/lib/chef/win32/api.rb +9 -2
  44. data/spec/data/knife-home/.chef/plugins/knife/example_home_subcommand.rb +0 -0
  45. data/spec/data/knife-site-subcommands/plugins/knife/example_subcommand.rb +0 -0
  46. data/spec/data/knife_subcommand/test_explicit_category.rb +7 -0
  47. data/spec/data/knife_subcommand/test_name_mapping.rb +4 -0
  48. data/spec/data/knife_subcommand/test_yourself.rb +21 -0
  49. data/spec/functional/resource/dnf_package_spec.rb +857 -537
  50. data/spec/functional/resource/group_spec.rb +1 -1
  51. data/spec/functional/resource/link_spec.rb +1 -1
  52. data/spec/functional/resource/remote_file_spec.rb +1 -1
  53. data/spec/functional/resource/windows_env_spec.rb +2 -2
  54. data/spec/functional/resource/yum_package_spec.rb +495 -428
  55. data/spec/integration/client/client_spec.rb +0 -20
  56. data/spec/integration/recipes/unified_mode_spec.rb +70 -0
  57. data/spec/spec_helper.rb +3 -0
  58. data/spec/support/chef_helpers.rb +1 -1
  59. data/spec/support/shared/functional/execute_resource.rb +1 -1
  60. data/spec/support/shared/functional/knife.rb +37 -0
  61. data/spec/support/shared/integration/knife_support.rb +192 -0
  62. data/spec/support/shared/unit/knife_shared.rb +39 -0
  63. data/spec/support/shared/unit/provider/file.rb +1 -1
  64. data/spec/unit/chef_fs/file_system/repository/directory_spec.rb +1 -1
  65. data/spec/unit/compliance/runner_spec.rb +1 -1
  66. data/spec/unit/provider/link_spec.rb +1 -1
  67. data/spec/unit/provider/package/dnf/python_helper_spec.rb +1 -0
  68. data/spec/unit/provider/package/yum/python_helper_spec.rb +1 -0
  69. data/spec/unit/provider/service/systemd_service_spec.rb +2 -2
  70. data/spec/unit/provider/systemd_unit_spec.rb +2 -2
  71. data/spec/unit/resource/inspec_waiver_file_entry_spec.rb +80 -0
  72. data/tasks/rspec.rb +4 -9
  73. metadata +16 -160
  74. data/lib/chef/provider/package/yum/simplejson/LICENSE.txt +0 -79
  75. data/lib/chef/provider/package/yum/simplejson/__init__.py +0 -318
  76. data/lib/chef/provider/package/yum/simplejson/__init__.pyc +0 -0
  77. data/lib/chef/provider/package/yum/simplejson/decoder.py +0 -354
  78. data/lib/chef/provider/package/yum/simplejson/decoder.pyc +0 -0
  79. data/lib/chef/provider/package/yum/simplejson/encoder.py +0 -440
  80. data/lib/chef/provider/package/yum/simplejson/encoder.pyc +0 -0
  81. data/lib/chef/provider/package/yum/simplejson/scanner.py +0 -65
  82. data/lib/chef/provider/package/yum/simplejson/scanner.pyc +0 -0
  83. data/lib/chef/provider/package/yum/simplejson/tool.py +0 -37
@@ -2,45 +2,26 @@
2
2
  # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
3
3
 
4
4
  #
5
- # NOTE: this actually needs to run under python2.4 and centos 5.x through python3 and centos 7.x
6
- # please manually test changes on centos5 boxes or you will almost certainly break things.
5
+ # NOTE: this actually needs to run under python2.7 and centos 6.x through python3 and centos 7.x
6
+ # please manually test changes on centos6 boxes or you will almost certainly break things.
7
7
  #
8
8
 
9
9
  import sys
10
10
  import yum
11
11
  import signal
12
12
  import os
13
- sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'simplejson'))
14
- try: import json
15
- except ImportError: import simplejson as json
13
+ import fcntl
14
+ import json
16
15
  import re
17
16
  from rpmUtils.miscutils import stringToVersion,compareEVR
18
17
  from rpmUtils.arch import getBaseArch, getArchList
19
-
20
-
21
- try: from yum.misc import string_to_prco_tuple
22
- except ImportError:
23
- # RHEL5 compat
24
- def string_to_prco_tuple(prcoString):
25
- prco_split = prcoString.split()
26
- n, f, v = prco_split
27
- (prco_e, prco_v, prco_r) = stringToVersion(v)
28
- return (n, f, (prco_e, prco_v, prco_r))
18
+ from yum.misc import string_to_prco_tuple
29
19
 
30
20
  # hack to work around https://github.com/chef/chef/issues/7126
31
21
  # see https://bugzilla.redhat.com/show_bug.cgi?id=1396248
32
22
  if not hasattr(yum.packages.FakeRepository, 'compare_providers_priority'):
33
23
  yum.packages.FakeRepository.compare_providers_priority = 99
34
24
 
35
- base = None
36
-
37
- def get_base():
38
- global base
39
- if base is None:
40
- base = yum.YumBase()
41
- setup_exit_handler()
42
- return base
43
-
44
25
  def versioncompare(versions):
45
26
  arch_list = getArchList()
46
27
  candidate_arch1 = versions[0].split(".")[-1]
@@ -51,9 +32,9 @@ def versioncompare(versions):
51
32
  # then we'll chop the arch component (assuming it *is* a valid one) from the first version string
52
33
  # so we're only comparing the evr portions.
53
34
  if (candidate_arch2 not in arch_list) and (candidate_arch1 in arch_list):
54
- final_version1 = versions[0].replace("." + candidate_arch1,"")
35
+ final_version1 = versions[0].replace("." + candidate_arch1,"")
55
36
  else:
56
- final_version1 = versions[0]
37
+ final_version1 = versions[0]
57
38
 
58
39
  final_version2 = versions[1]
59
40
 
@@ -64,37 +45,24 @@ def versioncompare(versions):
64
45
  outpipe.write("%(e)s\n" % { 'e': evr_comparison })
65
46
  outpipe.flush()
66
47
 
67
- def install_only_packages(name):
68
- base = get_base()
48
+ def install_only_packages(base, name):
69
49
  if name in base.conf.installonlypkgs:
70
- outpipe.write('True')
50
+ outpipe.write('True\n')
71
51
  else:
72
- outpipe.write('False')
52
+ outpipe.write('False\n')
73
53
  outpipe.flush()
74
54
 
75
- # python2.4 / centos5 compat
76
- try:
77
- any
78
- except NameError:
79
- def any(s):
80
- for v in s:
81
- if v:
82
- return True
83
- return False
84
-
85
- def query(command):
86
- base = get_base()
87
-
55
+ def query(base, command):
88
56
  enabled_repos = base.repos.listEnabled()
89
57
 
90
58
  # Handle any repocontrols passed in with our options
91
59
 
92
60
  if 'repos' in command:
93
- for repo in command['repos']:
94
- if 'enable' in repo:
95
- base.repos.enableRepo(repo['enable'])
61
+ for repo in command['repos']:
62
+ if 'enable' in repo:
63
+ base.repos.enableRepo(repo['enable'])
96
64
  if 'disable' in repo:
97
- base.repos.disableRepo(repo['disable'])
65
+ base.repos.disableRepo(repo['disable'])
98
66
 
99
67
  args = { 'name': command['provides'] }
100
68
  do_nevra = False
@@ -136,7 +104,7 @@ def query(command):
136
104
  # returnPackages and searchProvides and then apply the Nevra filters to those results.
137
105
  pkgs = obj.searchNevra(**args)
138
106
  if (command['action'] == "whatinstalled") and (not pkgs):
139
- pkgs = obj.searchNevra(name=args['name'], arch=desired_arch)
107
+ pkgs = obj.searchNevra(name=args['name'], arch=desired_arch)
140
108
  else:
141
109
  pats = [command['provides']]
142
110
  pkgs = obj.returnPackages(patterns=pats)
@@ -157,13 +125,13 @@ def query(command):
157
125
 
158
126
  # Reset any repos we were passed in enablerepo/disablerepo to the original state in enabled_repos
159
127
  if 'repos' in command:
160
- for repo in command['repos']:
161
- if 'enable' in repo:
162
- if base.repos.getRepo(repo['enable']) not in enabled_repos:
163
- base.repos.disableRepo(repo['enable'])
128
+ for repo in command['repos']:
129
+ if 'enable' in repo:
130
+ if base.repos.getRepo(repo['enable']) not in enabled_repos:
131
+ base.repos.disableRepo(repo['enable'])
164
132
  if 'disable' in repo:
165
- if base.repos.getRepo(repo['disable']) in enabled_repos:
166
- base.repos.enableRepo(repo['disable'])
133
+ if base.repos.getRepo(repo['disable']) in enabled_repos:
134
+ base.repos.enableRepo(repo['disable'])
167
135
 
168
136
  # the design of this helper is that it should try to be 'brittle' and fail hard and exit in order
169
137
  # to keep process tables clean. additional error handling should probably be added to the retry loop
@@ -179,21 +147,29 @@ def setup_exit_handler():
179
147
  signal.signal(signal.SIGPIPE, exit_handler)
180
148
  signal.signal(signal.SIGQUIT, exit_handler)
181
149
 
150
+ def set_blocking(fd):
151
+ old_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
152
+ fcntl.fcntl(fd, fcntl.F_SETFL, old_flags & ~os.O_NONBLOCK)
153
+
154
+ base = None
155
+
182
156
  if len(sys.argv) < 3:
183
- inpipe = sys.stdin
184
- outpipe = sys.stdout
157
+ inpipe = sys.stdin
158
+ outpipe = sys.stdout
185
159
  else:
186
- inpipe = os.fdopen(int(sys.argv[1]), "r")
187
- outpipe = os.fdopen(int(sys.argv[2]), "w")
160
+ set_blocking(int(sys.argv[1]))
161
+ set_blocking(int(sys.argv[2]))
162
+ inpipe = os.fdopen(int(sys.argv[1]), "r")
163
+ outpipe = os.fdopen(int(sys.argv[2]), "w")
188
164
 
189
165
  try:
166
+ setup_exit_handler()
190
167
  while 1:
191
168
  # stop the process if the parent proc goes away
192
169
  ppid = os.getppid()
193
170
  if ppid == 1:
194
171
  raise RuntimeError("orphaned")
195
172
 
196
- setup_exit_handler()
197
173
  line = inpipe.readline()
198
174
 
199
175
  # only way to detect EOF in python
@@ -205,14 +181,22 @@ try:
205
181
  except ValueError, e:
206
182
  raise RuntimeError("bad json parse")
207
183
 
184
+ if base is None:
185
+ base = yum.YumBase()
186
+
208
187
  if command['action'] == "whatinstalled":
209
- query(command)
188
+ query(base, command)
210
189
  elif command['action'] == "whatavailable":
211
- query(command)
190
+ query(base, command)
212
191
  elif command['action'] == "versioncompare":
213
192
  versioncompare(command['versions'])
214
193
  elif command['action'] == "installonlypkgs":
215
- install_only_packages(command['package'])
194
+ install_only_packages(base, command['package'])
195
+ elif command['action'] == "close_rpmdb":
196
+ base.closeRpmDB()
197
+ base = None
198
+ outpipe.write('nil nil nil\n')
199
+ outpipe.flush()
216
200
  else:
217
201
  raise RuntimeError("bad command")
218
202
  finally:
@@ -78,7 +78,7 @@ class Chef
78
78
  def define_resource_requirements
79
79
  requirements.assert(:create, :create_if_missing, :delete, :delete_key) do |a|
80
80
  a.assertion { registry.hive_exists?(new_resource.key) }
81
- a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{new_resource.key.split('\\').shift} does not exist")
81
+ a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{new_resource.key.split("\\").shift} does not exist")
82
82
  end
83
83
 
84
84
  requirements.assert(:create) do |a|
@@ -80,7 +80,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
80
80
  @systemd_service_status ||= begin
81
81
  # Collect all the status information for a service and returns it at once
82
82
  options, args = get_systemctl_options_args
83
- s = shell_out!(systemctl_path, args, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.service_name, options)
83
+ s = shell_out!(systemctl_path, args, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.service_name, **options)
84
84
  # e.g. /bin/systemctl --system show -p UnitFileState -p ActiveState sshd.service
85
85
  # Returns something like:
86
86
  # ActiveState=active
@@ -60,7 +60,7 @@ class Chef
60
60
  # Collect all the status information for a unit and return it at once
61
61
  # This may fail if we are managing a template unit (e.g. with '@'), in which case
62
62
  # we just ignore the error because unit status is irrelevant in that case
63
- s = shell_out(*systemctl_cmd, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.unit_name, systemctl_opts)
63
+ s = shell_out(*systemctl_cmd, "show", "-p", "UnitFileState", "-p", "ActiveState", new_resource.unit_name, **systemctl_opts)
64
64
  # e.g. /bin/systemctl --system show -p UnitFileState -p ActiveState syslog.socket
65
65
  # Returns something like:
66
66
  # ActiveState=inactive
@@ -63,7 +63,7 @@ class Chef
63
63
  context[:template_finder] = template_finder
64
64
 
65
65
  # helper variables
66
- context[:cookbook_name] = new_resource.cookbook_name unless context.keys.include?(:coookbook_name)
66
+ context[:cookbook_name] = new_resource.cookbook_name unless context.keys.include?(:cookbook_name)
67
67
  context[:recipe_name] = new_resource.recipe_name unless context.keys.include?(:recipe_name)
68
68
  context[:recipe_line_string] = new_resource.source_line unless context.keys.include?(:recipe_line_string)
69
69
  context[:recipe_path] = new_resource.source_line_file unless context.keys.include?(:recipe_path)
@@ -83,7 +83,7 @@ class Chef
83
83
  username = new_resource.user
84
84
 
85
85
  if new_resource.domain
86
- username = new_resource.domain + '\\' + new_resource.user
86
+ username = new_resource.domain + "\\" + new_resource.user
87
87
  end
88
88
 
89
89
  # Create an ACE that allows the alternate user read access to the script
data/lib/chef/resource.rb CHANGED
@@ -42,6 +42,7 @@ require_relative "mixin/deprecation"
42
42
  require_relative "mixin/properties"
43
43
  require_relative "mixin/provides"
44
44
  require_relative "dsl/universal"
45
+ require_relative "constants"
45
46
 
46
47
  class Chef
47
48
  class Resource
@@ -1362,8 +1363,9 @@ class Chef
1362
1363
  #
1363
1364
  # @param arg [String] version constraint to match against (e.g. "> 14")
1364
1365
  #
1365
- def self.chef_version_for_provides(constraint)
1366
- @chef_version_for_provides = constraint
1366
+ def self.chef_version_for_provides(constraint = NOT_PASSED)
1367
+ @chef_version_for_provides = constraint unless constraint == NOT_PASSED
1368
+ @chef_version_for_provides ||= nil
1367
1369
  end
1368
1370
 
1369
1371
  # Mark this resource as providing particular DSL.
@@ -1376,14 +1378,11 @@ class Chef
1376
1378
  def self.provides(name, **options, &block)
1377
1379
  name = name.to_sym
1378
1380
 
1379
- # quell warnings
1380
- @chef_version_for_provides = nil unless defined?(@chef_version_for_provides)
1381
-
1382
1381
  # deliberately do not go through the accessor here
1383
1382
  @resource_name = name if resource_name.nil?
1384
1383
 
1385
- if @chef_version_for_provides && !options.include?(:chef_version)
1386
- options[:chef_version] = @chef_version_for_provides
1384
+ if chef_version_for_provides && !options.include?(:chef_version)
1385
+ options[:chef_version] = chef_version_for_provides
1387
1386
  end
1388
1387
 
1389
1388
  result = Chef.resource_handler_map.set(name, self, **options, &block)
@@ -633,13 +633,13 @@ class Chef
633
633
  end
634
634
 
635
635
  # if domain is provided in both username and domain
636
- if specified_user.is_a?(String) && ((specified_user.include? '\\') || (specified_user.include? "@")) && specified_domain
636
+ if specified_user.is_a?(String) && ((specified_user.include? "\\") || (specified_user.include? "@")) && specified_domain
637
637
  raise ArgumentError, "The domain is provided twice. Username: `#{specified_user}`, Domain: `#{specified_domain}`. Please specify domain only once."
638
638
  end
639
639
 
640
640
  if specified_user.is_a?(String) && specified_domain.nil?
641
641
  # Splitting username of format: Domain\Username
642
- domain_and_user = user.split('\\')
642
+ domain_and_user = user.split("\\")
643
643
 
644
644
  if domain_and_user.length == 2
645
645
  domain = domain_and_user[0]
@@ -0,0 +1,155 @@
1
+ #
2
+ # Author:: Davin Taddeo (<davin@chef.io>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
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_relative "../resource"
19
+ require "yaml"
20
+ require "date"
21
+
22
+ class Chef
23
+ class Resource
24
+ class InspecWaiverFileEntry < Chef::Resource
25
+ provides :inspec_waiver_file_entry
26
+ unified_mode true
27
+
28
+ description "Use the **inspec_waiver_file_entry** resource to add or remove entries from an InSpec waiver file. This can be used in conjunction with the Compliance Phase."
29
+ introduced "17.1"
30
+ examples <<~DOC
31
+ **Add an InSpec waiver entry to a given waiver file**:
32
+
33
+ ```ruby
34
+ inspec_waiver_file_entry 'Add waiver entry for control' do
35
+ file_path 'C:\\chef\\inspec_waiver_file.yml'
36
+ control 'my_inspec_control_01'
37
+ run_test false
38
+ justification "The subject of this control is not managed by Chef on the systems in policy group \#{node['policy_group']}"
39
+ expiration '2022-01-01'
40
+ action :add
41
+ end
42
+ ```
43
+
44
+ **Add an InSpec waiver entry to a given waiver file using the 'name' property to identify the control**:
45
+
46
+ ```ruby
47
+ inspec_waiver_file_entry 'my_inspec_control_01' do
48
+ justification "The subject of this control is not managed by Chef on the systems in policy group \#{node['policy_group']}"
49
+ action :add
50
+ end
51
+ ```
52
+
53
+ **Remove an InSpec waiver entry to a given waiver file**:
54
+
55
+ ```ruby
56
+ inspec_waiver_file_entry "my_inspec_control_01" do
57
+ action :remove
58
+ end
59
+ ```
60
+ DOC
61
+
62
+ property :control, String,
63
+ name_property: true,
64
+ description: "The name of the control being added or removed to the waiver file"
65
+
66
+ property :file_path, String,
67
+ required: true,
68
+ description: "The path to the waiver file being modified",
69
+ default: "#{ChefConfig::Config.etc_chef_dir}/inspec_waivers.yml",
70
+ default_description: "`/etc/chef/inspec_waivers.yml` on Linux/Unix and `C:\\chef\\inspec_waivers.yml` on Windows"
71
+
72
+ property :expiration, String,
73
+ description: "The expiration date of the given waiver - provided in YYYY-MM-DD format",
74
+ callbacks: {
75
+ "Expiration date should be a valid calendar date and match the following format: YYYY-MM-DD" => proc { |e|
76
+ re = Regexp.new('\d{4}-\d{2}-\d{2}$').freeze
77
+ if re.match?(e)
78
+ Date.valid_date?(*e.split("-").map(&:to_i))
79
+ else
80
+ e.nil?
81
+ end
82
+ },
83
+ }
84
+
85
+ property :run_test, [true, false],
86
+ description: "If present and true, the control will run and be reported, but failures in it won’t make the overall run fail. If absent or false, the control will not be run."
87
+
88
+ property :justification, String,
89
+ description: "Can be any text you want and might include a reason for the waiver as well as who signed off on the waiver."
90
+
91
+ property :backup, [false, Integer],
92
+ description: "The number of backups to be kept in /var/chef/backup (for UNIX- and Linux-based platforms) or C:/chef/backup (for the Microsoft Windows platform). Set to false to prevent backups from being kept.",
93
+ default: false
94
+
95
+ action :add do
96
+ if new_resource.justification.nil? || new_resource.justification == ""
97
+ raise Chef::Exceptions::ValidationFailed, "Entries in the InSpec waiver file must have a justification given, this parameter must have a value."
98
+ end
99
+
100
+ filename = new_resource.file_path
101
+ waiver_hash = load_waiver_file_to_hash(filename)
102
+ control_hash = {}
103
+ control_hash["expiration_date"] = new_resource.expiration.to_s unless new_resource.expiration.nil?
104
+ control_hash["run"] = new_resource.run_test unless new_resource.run_test.nil?
105
+ control_hash["justification"] = new_resource.justification.to_s
106
+
107
+ unless waiver_hash[new_resource.control] == control_hash
108
+ waiver_hash[new_resource.control] = control_hash
109
+ waiver_hash = waiver_hash.sort.to_h
110
+
111
+ file "Update Waiver File #{new_resource.file_path} to update waiver for control #{new_resource.control}" do
112
+ path new_resource.file_path
113
+ content waiver_hash.to_yaml
114
+ backup new_resource.backup
115
+ action :create
116
+ end
117
+ end
118
+ end
119
+
120
+ action :remove do
121
+ filename = new_resource.file_path
122
+ waiver_hash = load_waiver_file_to_hash(filename)
123
+ if waiver_hash.key?(new_resource.control)
124
+ waiver_hash.delete(new_resource.control)
125
+ waiver_hash = waiver_hash.sort.to_h
126
+ file "Update Waiver File #{new_resource.file_path} to remove waiver for control #{new_resource.control}" do
127
+ path new_resource.file_path
128
+ content waiver_hash.to_yaml
129
+ backup new_resource.backup
130
+ action :create
131
+ end
132
+ end
133
+ end
134
+
135
+ action_class do
136
+ def load_waiver_file_to_hash(file_name)
137
+ if file_name =~ %r{(/|C:\\).*(.yaml|.yml)}i
138
+ if ::File.exist?(file_name)
139
+ hash = ::YAML.load_file(file_name)
140
+ if hash == false || hash.nil? || hash == ""
141
+ {}
142
+ else
143
+ ::YAML.load_file(file_name)
144
+ end
145
+ else
146
+ {}
147
+ end
148
+ else
149
+ raise "Waiver files needs to be a YAML file which should have a .yaml or .yml extension -\"#{file_name}\" does not have an appropriate extension"
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end