chef 12.15.19-universal-mingw32 → 12.16.42-universal-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -1
  3. data/VERSION +1 -1
  4. data/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml +3 -1
  5. data/acceptance/Gemfile.lock +14 -14
  6. data/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb +3 -11
  7. data/distro/common/html/knife_bootstrap.html +1 -1
  8. data/distro/common/man/man1/README.md +2 -2
  9. data/distro/common/man/man1/knife-client.1 +1 -1
  10. data/lib/chef/application.rb +7 -15
  11. data/lib/chef/application/client.rb +2 -2
  12. data/lib/chef/application/solo.rb +1 -1
  13. data/lib/chef/chef_class.rb +1 -0
  14. data/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb +3 -7
  15. data/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb +1 -1
  16. data/lib/chef/data_collector.rb +83 -9
  17. data/lib/chef/data_collector/messages.rb +2 -1
  18. data/lib/chef/dsl/core.rb +1 -1
  19. data/lib/chef/dsl/declare_resource.rb +10 -4
  20. data/lib/chef/dsl/method_missing.rb +1 -1
  21. data/lib/chef/dsl/recipe.rb +1 -1
  22. data/lib/chef/dsl/universal.rb +1 -1
  23. data/lib/chef/event_dispatch/base.rb +3 -0
  24. data/lib/chef/http.rb +3 -4
  25. data/lib/chef/knife.rb +20 -2
  26. data/lib/chef/knife/core/generic_presenter.rb +18 -4
  27. data/lib/chef/knife/node_show.rb +0 -5
  28. data/lib/chef/knife/osc_user_show.rb +0 -1
  29. data/lib/chef/knife/ssl_fetch.rb +9 -5
  30. data/lib/chef/mixin/powershell_out.rb +1 -1
  31. data/lib/chef/mixin/shell_out.rb +1 -1
  32. data/lib/chef/node.rb +1 -5
  33. data/lib/chef/node/attribute.rb +70 -98
  34. data/lib/chef/node/attribute_collections.rb +28 -19
  35. data/lib/chef/node/common_api.rb +0 -6
  36. data/lib/chef/node/immutable_collections.rb +16 -79
  37. data/lib/chef/node/mixin/deep_merge_cache.rb +61 -0
  38. data/lib/chef/node/mixin/immutablize_array.rb +67 -0
  39. data/lib/chef/node/mixin/immutablize_hash.rb +54 -0
  40. data/lib/chef/node/mixin/state_tracking.rb +93 -0
  41. data/lib/chef/property.rb +4 -4
  42. data/lib/chef/provider/cron.rb +1 -1
  43. data/lib/chef/provider/group/suse.rb +23 -4
  44. data/lib/chef/provider/package.rb +43 -5
  45. data/lib/chef/provider/package/apt.rb +20 -0
  46. data/lib/chef/provider/package/windows/exe.rb +4 -3
  47. data/lib/chef/provider/package/windows/msi.rb +4 -3
  48. data/lib/chef/provider/package/yum.rb +20 -0
  49. data/lib/chef/provider/package/zypper.rb +20 -0
  50. data/lib/chef/provider/ruby_block.rb +1 -1
  51. data/lib/chef/provider/service/upstart.rb +25 -9
  52. data/lib/chef/provider/user.rb +4 -6
  53. data/lib/chef/provider/user/dscl.rb +8 -3
  54. data/lib/chef/provider/user/solaris.rb +5 -12
  55. data/lib/chef/resource.rb +19 -0
  56. data/lib/chef/resource/file.rb +1 -1
  57. data/lib/chef/resource/package.rb +1 -1
  58. data/lib/chef/resource/scm.rb +1 -7
  59. data/lib/chef/resource/yum_repository.rb +1 -1
  60. data/lib/chef/rest.rb +1 -0
  61. data/lib/chef/run_context.rb +12 -0
  62. data/lib/chef/version.rb +1 -1
  63. data/spec/data/trusted_certs/example_no_cn.crt +36 -0
  64. data/spec/functional/resource/group_spec.rb +1 -0
  65. data/spec/functional/resource/user/useradd_spec.rb +4 -2
  66. data/spec/integration/knife/data_bag_create_spec.rb +0 -3
  67. data/spec/integration/knife/environment_show_spec.rb +24 -4
  68. data/spec/integration/knife/node_environment_set_spec.rb +4 -1
  69. data/spec/integration/recipes/accumulator_spec.rb +232 -0
  70. data/spec/integration/recipes/resource_action_spec.rb +1 -1
  71. data/spec/spec_helper.rb +2 -2
  72. data/spec/support/shared/context/client.rb +12 -3
  73. data/spec/support/shared/integration/app_server_support.rb +1 -1
  74. data/spec/support/shared/integration/knife_support.rb +4 -1
  75. data/spec/unit/data_collector/messages_spec.rb +2 -0
  76. data/spec/unit/data_collector_spec.rb +158 -21
  77. data/spec/unit/http_spec.rb +1 -1
  78. data/spec/unit/knife/core/gem_glob_loader_spec.rb +1 -1
  79. data/spec/unit/knife/core/ui_spec.rb +10 -0
  80. data/spec/unit/knife/ssl_fetch_spec.rb +38 -0
  81. data/spec/unit/knife_spec.rb +31 -0
  82. data/spec/unit/mixin/powershell_out_spec.rb +25 -1
  83. data/spec/unit/node/attribute_spec.rb +46 -1
  84. data/spec/unit/node/vivid_mash_spec.rb +27 -89
  85. data/spec/unit/node_spec.rb +134 -3
  86. data/spec/unit/provider/deploy_spec.rb +1 -1
  87. data/spec/unit/provider/group/suse_spec.rb +90 -0
  88. data/spec/unit/provider/package/apt_spec.rb +22 -0
  89. data/spec/unit/provider/package/windows/msi_spec.rb +13 -4
  90. data/spec/unit/provider/package/windows_spec.rb +3 -3
  91. data/spec/unit/provider/package/yum_spec.rb +18 -0
  92. data/spec/unit/provider/package/zypper_spec.rb +64 -0
  93. data/spec/unit/provider/package_spec.rb +58 -0
  94. data/spec/unit/provider/remote_file/content_spec.rb +1 -1
  95. data/spec/unit/provider/service/upstart_service_spec.rb +13 -6
  96. data/spec/unit/provider/user/solaris_spec.rb +36 -9
  97. data/spec/unit/provider/user_spec.rb +6 -0
  98. data/spec/unit/resource/apt_repository_spec.rb +1 -1
  99. metadata +12 -5
@@ -0,0 +1,54 @@
1
+ #--
2
+ # Copyright:: Copyright 2016, 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
+ class Chef
19
+ class Node
20
+ module Mixin
21
+ module ImmutablizeHash
22
+ DISALLOWED_MUTATOR_METHODS = [
23
+ :[]=,
24
+ :clear,
25
+ :collect!,
26
+ :default=,
27
+ :default_proc=,
28
+ :delete,
29
+ :delete_if,
30
+ :keep_if,
31
+ :map!,
32
+ :merge!,
33
+ :update,
34
+ :reject!,
35
+ :replace,
36
+ :select!,
37
+ :shift,
38
+ :write,
39
+ :write!,
40
+ :unlink,
41
+ :unlink!,
42
+ ]
43
+
44
+ # Redefine all of the methods that mutate a Hash to raise an error when called.
45
+ # This is the magic that makes this object "Immutable"
46
+ DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
47
+ define_method(mutator_method_name) do |*args, &block|
48
+ raise Exceptions::ImmutableAttributeModification
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,93 @@
1
+ #--
2
+ # Copyright:: Copyright 2016, 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
+ class Chef
19
+ class Node
20
+ module Mixin
21
+ module StateTracking
22
+ attr_reader :__path__
23
+ attr_reader :__root__
24
+ attr_reader :__node__
25
+ attr_reader :__precedence__
26
+
27
+ def initialize(data = nil, root = self, node = nil, precedence = nil)
28
+ # __path__ and __root__ must be nil when we call super so it knows
29
+ # to avoid resetting the cache on construction
30
+ data.nil? ? super() : super(data)
31
+ @__path__ = []
32
+ @__root__ = root
33
+ @__node__ = node
34
+ @__precedence__ = precedence
35
+ end
36
+
37
+ def [](key)
38
+ ret = super
39
+ next_path = [ __path__, convert_key(key) ].flatten.compact
40
+ copy_state_to(ret, next_path)
41
+ end
42
+
43
+ def []=(key, value)
44
+ ret = super
45
+ next_path = [ __path__, convert_key(key) ].flatten.compact
46
+ send_attribute_changed_event(next_path, value)
47
+ copy_state_to(ret, next_path)
48
+ end
49
+
50
+ protected
51
+
52
+ def __path__=(path)
53
+ @__path__ = path
54
+ end
55
+
56
+ def __root__=(root)
57
+ @__root__ = root
58
+ end
59
+
60
+ def __precedence__=(precedence)
61
+ @__precedence__ = precedence
62
+ end
63
+
64
+ def __node__=(node)
65
+ @__node__ = node
66
+ end
67
+
68
+ private
69
+
70
+ def send_attribute_changed_event(next_path, value)
71
+ if __node__ && __node__.run_context && __node__.run_context.events
72
+ __node__.run_context.events.attribute_changed(__precedence__, next_path, value)
73
+ end
74
+ end
75
+
76
+ def send_reset_cache(path = nil, key = nil)
77
+ next_path = [ path, key ].flatten.compact
78
+ __root__.reset_cache(next_path.first) if !__root__.nil? && __root__.respond_to?(:reset_cache) && !next_path.nil?
79
+ end
80
+
81
+ def copy_state_to(ret, next_path)
82
+ if ret.is_a?(StateTracking)
83
+ ret.__path__ = next_path
84
+ ret.__root__ = __root__
85
+ ret.__node__ = __node__
86
+ ret.__precedence__ = __precedence__
87
+ end
88
+ ret
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -522,22 +522,22 @@ class Chef
522
522
  # stack trace if you use `define_method`.
523
523
  declared_in.class_eval <<-EOM, __FILE__, __LINE__ + 1
524
524
  def #{name}(value=NOT_PASSED)
525
- raise "Property #{name} of \#{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block_given?
525
+ raise "Property `#{name}` of `\#{self}` was incorrectly passed a block. Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block_given?
526
526
  self.class.properties[#{name.inspect}].call(self, value)
527
527
  end
528
528
  def #{name}=(value)
529
- raise "Property #{name} of \#{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block_given?
529
+ raise "Property `#{name}` of `\#{self}` was incorrectly passed a block. Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block_given?
530
530
  self.class.properties[#{name.inspect}].set(self, value)
531
531
  end
532
532
  EOM
533
533
  rescue SyntaxError
534
534
  # If the name is not a valid ruby name, we use define_method.
535
535
  declared_in.define_method(name) do |value = NOT_PASSED, &block|
536
- raise "Property #{name} of #{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block
536
+ raise "Property `#{name}` of `#{self}` was incorrectly passed a block! Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block
537
537
  self.class.properties[name].call(self, value)
538
538
  end
539
539
  declared_in.define_method("#{name}=") do |value, &block|
540
- raise "Property #{name} of #{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block
540
+ raise "Property `#{name}` of `#{self}` was incorrectly passed a block! Possible property-resource collision. To call a resource named `#{name}` either rename the property or else use `declare_resource(:#{name}, ...)`" if block
541
541
  self.class.properties[name].set(self, value)
542
542
  end
543
543
  end
@@ -199,7 +199,7 @@ class Chef
199
199
 
200
200
  def set_environment_var(attr_name, attr_value)
201
201
  if %w{MAILTO PATH SHELL HOME}.include?(attr_name)
202
- @current_resource.send(attr_name.downcase.to_sym, attr_value)
202
+ @current_resource.send(attr_name.downcase.to_sym, attr_value.gsub(/^"|"$/, ""))
203
203
  else
204
204
  @current_resource.environment(@current_resource.environment.merge(attr_name => attr_value))
205
205
  end
@@ -17,6 +17,7 @@
17
17
  #
18
18
 
19
19
  require "chef/provider/group/groupadd"
20
+ require "etc"
20
21
 
21
22
  class Chef
22
23
  class Provider
@@ -36,24 +37,42 @@ class Chef
36
37
  a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{@new_resource.name}"
37
38
  # No whyrun alternative: this component should be available in the base install of any given system that uses it
38
39
  end
40
+
41
+ requirements.assert(:create, :manage, :modify) do |a|
42
+ a.assertion do
43
+ begin
44
+ to_add(@new_resource.members).all? { |member| Etc.getpwnam(member) }
45
+ rescue
46
+ false
47
+ end
48
+ end
49
+ a.failure_message Chef::Exceptions::Group, "Could not add users #{to_add(@new_resource.members).join(", ")} to #{@new_resource.group_name}: one of these users does not exist"
50
+ a.whyrun "Could not find one of these users: #{to_add(@new_resource.members).join(", ")}. Assuming it will be created by a prior step"
51
+ end
39
52
  end
40
53
 
41
54
  def set_members(members)
42
- to_delete = @current_resource.members - members
43
- to_delete.each do |member|
55
+ to_remove(members).each do |member|
44
56
  remove_member(member)
45
57
  end
46
58
 
47
- to_add = members - @current_resource.members
48
- to_add.each do |member|
59
+ to_add(members).each do |member|
49
60
  add_member(member)
50
61
  end
51
62
  end
52
63
 
64
+ def to_add(members)
65
+ members - @current_resource.members
66
+ end
67
+
53
68
  def add_member(member)
54
69
  shell_out!("groupmod -A #{member} #{@new_resource.group_name}")
55
70
  end
56
71
 
72
+ def to_remove(members)
73
+ @current_resource.members - members
74
+ end
75
+
57
76
  def remove_member(member)
58
77
  shell_out!("groupmod -R #{member} #{@new_resource.group_name}")
59
78
  end
@@ -31,6 +31,8 @@ class Chef
31
31
  include Chef::Mixin::ShellOut
32
32
  extend Chef::Mixin::SubclassDirective
33
33
 
34
+ use_inline_resources
35
+
34
36
  # subclasses declare this if they want all their arguments as arrays of packages and names
35
37
  subclass_directive :use_multipackage_api
36
38
  # subclasses declare this if they want sources (filenames) pulled from their package names
@@ -81,7 +83,7 @@ class Chef
81
83
  end
82
84
  end
83
85
 
84
- def action_install
86
+ action :install do
85
87
  unless target_version_array.any?
86
88
  Chef::Log.debug("#{@new_resource} is already installed - nothing to do")
87
89
  return
@@ -116,7 +118,7 @@ class Chef
116
118
 
117
119
  private :install_description
118
120
 
119
- def action_upgrade
121
+ action :upgrade do
120
122
  if !target_version_array.any?
121
123
  Chef::Log.debug("#{@new_resource} no versions to upgrade - nothing to do")
122
124
  return
@@ -146,7 +148,7 @@ class Chef
146
148
 
147
149
  private :upgrade_description
148
150
 
149
- def action_remove
151
+ action :remove do
150
152
  if removing_package?
151
153
  description = @new_resource.version ? "version #{@new_resource.version} of " : ""
152
154
  converge_by("remove #{description}package #{@current_resource.package_name}") do
@@ -181,7 +183,7 @@ class Chef
181
183
  end
182
184
  end
183
185
 
184
- def action_purge
186
+ action :purge do
185
187
  if removing_package?
186
188
  description = @new_resource.version ? "version #{@new_resource.version} of" : ""
187
189
  converge_by("purge #{description} package #{@current_resource.package_name}") do
@@ -193,7 +195,7 @@ class Chef
193
195
  end
194
196
  end
195
197
 
196
- def action_reconfig
198
+ action :reconfig do
197
199
  if @current_resource.version == nil
198
200
  Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do")
199
201
  return
@@ -218,6 +220,34 @@ class Chef
218
220
  end
219
221
  end
220
222
 
223
+ def action_lock
224
+ if package_locked(@new_resource.name, @new_resource.version) == false
225
+ description = @new_resource.version ? "version #{@new_resource.version} of " : ""
226
+ converge_by("lock #{description}package #{@current_resource.package_name}") do
227
+ multipackage_api_adapter(@current_resource.package_name, @new_resource.version) do |name, version|
228
+ lock_package(name, version)
229
+ Chef::Log.info("#{@new_resource} locked")
230
+ end
231
+ end
232
+ else
233
+ Chef::Log.debug("#{new_resource} is already locked")
234
+ end
235
+ end
236
+
237
+ def action_unlock
238
+ if package_locked(@new_resource.name, @new_resource.version) == true
239
+ description = @new_resource.version ? "version #{@new_resource.version} of " : ""
240
+ converge_by("unlock #{description}package #{@current_resource.package_name}") do
241
+ multipackage_api_adapter(@current_resource.package_name, @new_resource.version) do |name, version|
242
+ unlock_package(name, version)
243
+ Chef::Log.info("#{@new_resource} unlocked")
244
+ end
245
+ end
246
+ else
247
+ Chef::Log.debug("#{new_resource} is already unlocked")
248
+ end
249
+ end
250
+
221
251
  # @todo use composition rather than inheritance
222
252
 
223
253
  def multipackage_api_adapter(name, version)
@@ -252,6 +282,14 @@ class Chef
252
282
  raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :reconfig" )
253
283
  end
254
284
 
285
+ def lock_package(name, version)
286
+ raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :lock" )
287
+ end
288
+
289
+ def unlock_package(name, version)
290
+ raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :unlock" )
291
+ end
292
+
255
293
  # used by subclasses. deprecated. use #a_to_s instead.
256
294
  def expand_options(options)
257
295
  options ? " #{options}" : ""
@@ -70,6 +70,18 @@ class Chef
70
70
  @candidate_version ||= get_candidate_versions
71
71
  end
72
72
 
73
+ def package_locked(name, version)
74
+ islocked = false
75
+ locked = shell_out_with_timeout!("apt-mark showhold")
76
+ locked.stdout.each_line do |line|
77
+ line_package = line.strip
78
+ if line_package == name
79
+ islocked = true
80
+ end
81
+ end
82
+ return islocked
83
+ end
84
+
73
85
  def install_package(name, version)
74
86
  package_name = name.zip(version).map do |n, v|
75
87
  package_data[n][:virtual] ? n : "#{n}=#{v}"
@@ -105,6 +117,14 @@ class Chef
105
117
  run_noninteractive("dpkg-reconfigure", name)
106
118
  end
107
119
 
120
+ def lock_package(name, version)
121
+ run_noninteractive("apt-mark", new_resource.options, "hold", name)
122
+ end
123
+
124
+ def unlock_package(name, version)
125
+ run_noninteractive("apt-mark", new_resource.options, "unhold", name)
126
+ end
127
+
108
128
  private
109
129
 
110
130
  # Runs command via shell_out with magic environment to disable
@@ -89,9 +89,10 @@ class Chef
89
89
  end
90
90
 
91
91
  def current_installed_version
92
- @current_installed_version ||= uninstall_entries.count == 0 ? nil : begin
93
- uninstall_entries.map { |entry| entry.display_version }.uniq
94
- end
92
+ @current_installed_version ||=
93
+ if uninstall_entries.count != 0
94
+ uninstall_entries.map { |entry| entry.display_version }.uniq
95
+ end
95
96
  end
96
97
 
97
98
  # http://unattended.sourceforge.net/installers.php
@@ -50,7 +50,7 @@ class Chef
50
50
  Chef::Log.debug("#{new_resource} checking package status and version for #{product_code}")
51
51
  get_installed_version(product_code)
52
52
  else
53
- uninstall_entries.count == 0 ? nil : begin
53
+ if uninstall_entries.count != 0
54
54
  uninstall_entries.map { |entry| entry.display_version }.uniq
55
55
  end
56
56
  end
@@ -79,9 +79,10 @@ class Chef
79
79
  uninstall_version = new_resource.version || installed_version
80
80
  uninstall_entries.select { |entry| [uninstall_version].flatten.include?(entry.display_version) }
81
81
  .map { |version| version.uninstall_string }.uniq.each do |uninstall_string|
82
- Chef::Log.debug("#{new_resource} removing MSI package version using '#{uninstall_string}'")
82
+ uninstall_string = "msiexec /x #{uninstall_string.match(/{.*}/)}"
83
83
  uninstall_string += expand_options(new_resource.options)
84
- uninstall_string += " /Q" unless uninstall_string =~ / \/Q\b/
84
+ uninstall_string += " /q" unless uninstall_string.downcase =~ / \/q/
85
+ Chef::Log.debug("#{new_resource} removing MSI package version using '#{uninstall_string}'")
85
86
  shell_out!(uninstall_string, { :timeout => new_resource.timeout, :returns => new_resource.returns })
86
87
  end
87
88
  end
@@ -123,6 +123,18 @@ class Chef
123
123
  end
124
124
  end
125
125
 
126
+ def package_locked(name, version)
127
+ islocked = false
128
+ locked = shell_out_with_timeout!("yum versionlock")
129
+ locked.stdout.each_line do |line|
130
+ line_package = line.sub(/-[^-]*-[^-]*$/, "").split(":").last.strip
131
+ if line_package == name
132
+ islocked = true
133
+ end
134
+ end
135
+ return islocked
136
+ end
137
+
126
138
  # Standard Provider methods for Parent
127
139
  #
128
140
 
@@ -369,6 +381,14 @@ class Chef
369
381
  remove_package(name, version)
370
382
  end
371
383
 
384
+ def lock_package(name, version)
385
+ yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} versionlock add #{name}")
386
+ end
387
+
388
+ def unlock_package(name, version)
389
+ yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} versionlock delete #{name}")
390
+ end
391
+
372
392
  private
373
393
 
374
394
  def parse_arch(package_name)
@@ -75,6 +75,18 @@ class Chef
75
75
  end
76
76
  end
77
77
 
78
+ def package_locked(name, version)
79
+ islocked = false
80
+ locked = shell_out_with_timeout!("zypper locks")
81
+ locked.stdout.each_line do |line|
82
+ line_package = line.split("|").shift(2).last.strip
83
+ if line_package == name
84
+ islocked = true
85
+ end
86
+ end
87
+ return islocked
88
+ end
89
+
78
90
  def load_current_resource
79
91
  @current_resource = Chef::Resource::ZypperPackage.new(new_resource.name)
80
92
  current_resource.package_name(new_resource.package_name)
@@ -107,6 +119,14 @@ class Chef
107
119
  zypper_package("remove --clean-deps", name, version)
108
120
  end
109
121
 
122
+ def lock_package(name, version)
123
+ zypper_package("addlock", name, version)
124
+ end
125
+
126
+ def unlock_package(name, version)
127
+ zypper_package("removelock", name, version)
128
+ end
129
+
110
130
  private
111
131
 
112
132
  def zip(names, versions)