compat_resource 12.5.1

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.
@@ -0,0 +1,101 @@
1
+ require 'chef_compat/copied_from_chef'
2
+ module ChefCompat
3
+ module CopiedFromChef
4
+ class Chef < (defined?(::Chef) ? ::Chef : Object)
5
+ class Provider < (defined?(::Chef::Provider) ? ::Chef::Provider : Object)
6
+ def initialize(new_resource, run_context)
7
+ @new_resource = new_resource
8
+ @action = action
9
+ @current_resource = nil
10
+ @run_context = run_context
11
+ @converge_actions = nil
12
+
13
+ @recipe_name = nil
14
+ @cookbook_name = nil
15
+ self.class.include_resource_dsl_module(new_resource)
16
+ end
17
+ def converge_if_changed(*properties, &converge_block)
18
+ if !converge_block
19
+ raise ArgumentError, "converge_if_changed must be passed a block!"
20
+ end
21
+
22
+ properties = new_resource.class.state_properties.map { |p| p.name } if properties.empty?
23
+ properties = properties.map { |p| p.to_sym }
24
+ if current_resource
25
+ # Collect the list of modified properties
26
+ specified_properties = properties.select { |property| new_resource.property_is_set?(property) }
27
+ modified = specified_properties.select { |p| new_resource.send(p) != current_resource.send(p) }
28
+ if modified.empty?
29
+ Chef::Log.debug("Skipping update of #{new_resource.to_s}: has not changed any of the specified properties #{specified_properties.map { |p| "#{p}=#{new_resource.send(p).inspect}" }.join(", ")}.")
30
+ return false
31
+ end
32
+
33
+ # Print the pretty green text and run the block
34
+ property_size = modified.map { |p| p.size }.max
35
+ modified = modified.map { |p| " set #{p.to_s.ljust(property_size)} to #{new_resource.send(p).inspect} (was #{current_resource.send(p).inspect})" }
36
+ converge_by([ "update #{current_resource.identity}" ] + modified, &converge_block)
37
+
38
+ else
39
+ # The resource doesn't exist. Mark that we are *creating* this, and
40
+ # write down any properties we are setting.
41
+ property_size = properties.map { |p| p.size }.max
42
+ created = []
43
+ properties.each do |property|
44
+ if new_resource.property_is_set?(property)
45
+ created << " set #{property.to_s.ljust(property_size)} to #{new_resource.send(property).inspect}"
46
+ else
47
+ created << " set #{property.to_s.ljust(property_size)} to #{new_resource.send(property).inspect} (default value)"
48
+ end
49
+ end
50
+
51
+ converge_by([ "create #{new_resource.identity}" ] + created, &converge_block)
52
+ end
53
+ true
54
+ end
55
+ def self.include_resource_dsl(include_resource_dsl)
56
+ @include_resource_dsl = include_resource_dsl
57
+ end
58
+ def self.include_resource_dsl_module(resource)
59
+ if @include_resource_dsl && !defined?(@included_resource_dsl_module)
60
+ provider_class = self
61
+ @included_resource_dsl_module = Module.new do
62
+ extend Forwardable
63
+ define_singleton_method(:to_s) { "#{resource_class} forwarder module" }
64
+ define_singleton_method(:inspect) { to_s }
65
+ # Add a delegator for each explicit property that will get the *current* value
66
+ # of the property by default instead of the *actual* value.
67
+ resource.class.properties.each do |name, property|
68
+ class_eval(<<-EOM, __FILE__, __LINE__)
69
+ def #{name}(*args, &block)
70
+ # If no arguments were passed, we process "get" by defaulting
71
+ # the value to current_resource, not new_resource. This helps
72
+ # avoid issues where resources accidentally overwrite perfectly
73
+ # valid stuff with default values.
74
+ if args.empty? && !block
75
+ if !new_resource.property_is_set?(__method__) && current_resource
76
+ return current_resource.public_send(__method__)
77
+ end
78
+ end
79
+ new_resource.public_send(__method__, *args, &block)
80
+ end
81
+ EOM
82
+ end
83
+ dsl_methods =
84
+ resource.class.public_instance_methods +
85
+ resource.class.protected_instance_methods -
86
+ provider_class.instance_methods -
87
+ resource.class.properties.keys
88
+ def_delegators(:new_resource, *dsl_methods)
89
+ end
90
+ include @included_resource_dsl_module
91
+ end
92
+ end
93
+ def self.use_inline_resources
94
+ extend InlineResources::ClassMethods
95
+ include InlineResources
96
+ end
97
+ protected
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,283 @@
1
+ require 'chef_compat/copied_from_chef'
2
+ module ChefCompat
3
+ module CopiedFromChef
4
+ require 'chef_compat/copied_from_chef/chef/mixin/params_validate'
5
+ require 'chef_compat/copied_from_chef/chef/resource/action_class'
6
+ class Chef < (defined?(::Chef) ? ::Chef : Object)
7
+ class Resource < (defined?(::Chef::Resource) ? ::Chef::Resource : Object)
8
+ def initialize(name, run_context=nil)
9
+ name(name) unless name.nil?
10
+ @run_context = run_context
11
+ @noop = nil
12
+ @before = nil
13
+ @params = Hash.new
14
+ @provider = nil
15
+ @allowed_actions = self.class.allowed_actions.to_a
16
+ @action = self.class.default_action
17
+ @updated = false
18
+ @updated_by_last_action = false
19
+ @supports = {}
20
+ @ignore_failure = false
21
+ @retries = 0
22
+ @retry_delay = 2
23
+ @not_if = []
24
+ @only_if = []
25
+ @source_line = nil
26
+ # We would like to raise an error when the user gives us a guard
27
+ # interpreter and a ruby_block to the guard. In order to achieve this
28
+ # we need to understand when the user overrides the default guard
29
+ # interpreter. Therefore we store the default separately in a different
30
+ # attribute.
31
+ @guard_interpreter = nil
32
+ @default_guard_interpreter = :default
33
+ @elapsed_time = 0
34
+ @sensitive = false
35
+ end
36
+ def self.properties(include_superclass=true)
37
+ @properties ||= {}
38
+ if include_superclass
39
+ if superclass.respond_to?(:properties)
40
+ superclass.properties.merge(@properties)
41
+ else
42
+ @properties.dup
43
+ end
44
+ else
45
+ @properties
46
+ end
47
+ end
48
+ def action(arg=nil)
49
+ if arg
50
+ arg = Array(arg).map(&:to_sym)
51
+ arg.each do |action|
52
+ validate(
53
+ { action: action },
54
+ { action: { kind_of: Symbol, equal_to: allowed_actions } }
55
+ )
56
+ end
57
+ @action = arg
58
+ else
59
+ @action
60
+ end
61
+ end
62
+ alias_method :action=, :action
63
+ def state_for_resource_reporter
64
+ state = {}
65
+ state_properties = self.class.state_properties
66
+ state_properties.each do |property|
67
+ if property.identity? || property.is_set?(self)
68
+ state[property.name] = send(property.name)
69
+ end
70
+ end
71
+ state
72
+ end
73
+ alias_method :state, :state_for_resource_reporter
74
+ def identity
75
+ result = {}
76
+ identity_properties = self.class.identity_properties
77
+ identity_properties.each do |property|
78
+ result[property.name] = send(property.name)
79
+ end
80
+ return result.values.first if identity_properties.size == 1
81
+ result
82
+ end
83
+ include Chef::Mixin::ParamsValidate
84
+ def self.property(name, type=NOT_PASSED, **options)
85
+ name = name.to_sym
86
+
87
+ options.each { |k,v| options[k.to_sym] = v if k.is_a?(String) }
88
+
89
+ options[:instance_variable_name] = :"@#{name}" if !options.has_key?(:instance_variable_name)
90
+ options.merge!(name: name, declared_in: self)
91
+
92
+ if type == NOT_PASSED
93
+ # If a type is not passed, the property derives from the
94
+ # superclass property (if any)
95
+ if properties.has_key?(name)
96
+ property = properties[name].derive(**options)
97
+ else
98
+ property = property_type(**options)
99
+ end
100
+
101
+ # If a Property is specified, derive a new one from that.
102
+ elsif type.is_a?(Property) || (type.is_a?(Class) && type <= Property)
103
+ property = type.derive(**options)
104
+
105
+ # If a primitive type was passed, combine it with "is"
106
+ else
107
+ if options[:is]
108
+ options[:is] = ([ type ] + [ options[:is] ]).flatten(1)
109
+ else
110
+ options[:is] = type
111
+ end
112
+ property = property_type(**options)
113
+ end
114
+
115
+ local_properties = properties(false)
116
+ local_properties[name] = property
117
+
118
+ property.emit_dsl
119
+ end
120
+ def self.property_type(**options)
121
+ Property.derive(**options)
122
+ end
123
+ property :name, String, coerce: proc { |v| v.is_a?(Array) ? v.join(', ') : v.to_s }, desired_state: false
124
+ def property_is_set?(name)
125
+ property = self.class.properties[name.to_sym]
126
+ raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
127
+ property.is_set?(self)
128
+ end
129
+ def reset_property(name)
130
+ property = self.class.properties[name.to_sym]
131
+ raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
132
+ property.reset(self)
133
+ end
134
+ def self.lazy(&block)
135
+ DelayedEvaluator.new(&block)
136
+ end
137
+ def self.state_properties(*names)
138
+ if !names.empty?
139
+ names = names.map { |name| name.to_sym }.uniq
140
+
141
+ local_properties = properties(false)
142
+ # Add new properties to the list.
143
+ names.each do |name|
144
+ property = properties[name]
145
+ if !property
146
+ self.property name, instance_variable_name: false, desired_state: true
147
+ elsif !property.desired_state?
148
+ self.property name, desired_state: true
149
+ end
150
+ end
151
+
152
+ # If state_attrs *excludes* something which is currently desired state,
153
+ # mark it as desired_state: false.
154
+ local_properties.each do |name,property|
155
+ if property.desired_state? && !names.include?(name)
156
+ self.property name, desired_state: false
157
+ end
158
+ end
159
+ end
160
+
161
+ properties.values.select { |property| property.desired_state? }
162
+ end
163
+ def self.identity_properties(*names)
164
+ if !names.empty?
165
+ names = names.map { |name| name.to_sym }
166
+
167
+ # Add or change properties that are not part of the identity.
168
+ names.each do |name|
169
+ property = properties[name]
170
+ if !property
171
+ self.property name, instance_variable_name: false, identity: true
172
+ elsif !property.identity?
173
+ self.property name, identity: true
174
+ end
175
+ end
176
+
177
+ # If identity_properties *excludes* something which is currently part of
178
+ # the identity, mark it as identity: false.
179
+ properties.each do |name,property|
180
+ if property.identity? && !names.include?(name)
181
+ self.property name, identity: false
182
+ end
183
+ end
184
+ end
185
+
186
+ result = properties.values.select { |property| property.identity? }
187
+ result = [ properties[:name] ] if result.empty?
188
+ result
189
+ end
190
+ def self.identity_property(name=nil)
191
+ result = identity_properties(*Array(name))
192
+ if result.size > 1
193
+ raise Chef::Exceptions::MultipleIdentityError, "identity_property cannot be called on an object with more than one identity property (#{result.map { |r| r.name }.join(", ")})."
194
+ end
195
+ result.first
196
+ end
197
+ attr_accessor :allowed_actions
198
+ def allowed_actions(value=NOT_PASSED)
199
+ if value != NOT_PASSED
200
+ self.allowed_actions = value
201
+ end
202
+ @allowed_actions
203
+ end
204
+ def resource_name
205
+ @resource_name || self.class.resource_name
206
+ end
207
+ def self.use_automatic_resource_name
208
+ automatic_name = convert_to_snake_case(self.name.split('::')[-1])
209
+ resource_name automatic_name
210
+ end
211
+ def self.allowed_actions(*actions)
212
+ @allowed_actions ||=
213
+ if superclass.respond_to?(:allowed_actions)
214
+ superclass.allowed_actions.dup
215
+ else
216
+ [ :nothing ]
217
+ end
218
+ @allowed_actions |= actions.flatten
219
+ end
220
+ def self.allowed_actions=(value)
221
+ @allowed_actions = value.uniq
222
+ end
223
+ def self.default_action(action_name=NOT_PASSED)
224
+ unless action_name.equal?(NOT_PASSED)
225
+ @default_action = Array(action_name).map(&:to_sym)
226
+ self.allowed_actions |= @default_action
227
+ end
228
+
229
+ if @default_action
230
+ @default_action
231
+ elsif superclass.respond_to?(:default_action)
232
+ superclass.default_action
233
+ else
234
+ [:nothing]
235
+ end
236
+ end
237
+ def self.default_action=(action_name)
238
+ default_action action_name
239
+ end
240
+ def self.action(action, &recipe_block)
241
+ action = action.to_sym
242
+ declare_action_class
243
+ action_class.action(action, &recipe_block)
244
+ self.allowed_actions += [ action ]
245
+ default_action action if Array(default_action) == [:nothing]
246
+ end
247
+ def self.load_current_value(&load_block)
248
+ define_method(:load_current_value!, &load_block)
249
+ end
250
+ def current_value_does_not_exist!
251
+ raise Chef::Exceptions::CurrentValueDoesNotExist
252
+ end
253
+ def self.action_class
254
+ @action_class ||
255
+ # If the superclass needed one, then we need one as well.
256
+ if superclass.respond_to?(:action_class) && superclass.action_class
257
+ declare_action_class
258
+ end
259
+ end
260
+ def self.declare_action_class
261
+ return @action_class if @action_class
262
+
263
+ if superclass.respond_to?(:action_class)
264
+ base_provider = superclass.action_class
265
+ end
266
+ base_provider ||= Chef::Provider
267
+
268
+ resource_class = self
269
+ @action_class = Class.new(base_provider) do
270
+ include ActionClass
271
+ self.resource_class = resource_class
272
+ end
273
+ end
274
+ FORBIDDEN_IVARS = [:@run_context, :@not_if, :@only_if, :@enclosing_provider]
275
+ HIDDEN_IVARS = [:@allowed_actions, :@resource_name, :@source_line, :@run_context, :@name, :@not_if, :@only_if, :@elapsed_time, :@enclosing_provider]
276
+ class << self
277
+ end
278
+ @@sorted_descendants = nil
279
+ private
280
+ end
281
+ end
282
+ end
283
+ end
@@ -0,0 +1,97 @@
1
+ require 'chef_compat/copied_from_chef'
2
+ module ChefCompat
3
+ module CopiedFromChef
4
+ #
5
+ # Author:: John Keiser (<jkeiser@chef.io)
6
+ # Copyright:: Copyright (c) 2015 Opscode, Inc.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+
22
+
23
+ class Chef < (defined?(::Chef) ? ::Chef : Object)
24
+ class Resource < (defined?(::Chef::Resource) ? ::Chef::Resource : Object)
25
+ module ActionClass
26
+ if defined?(::Chef::Resource::ActionClass)
27
+ require 'chef_compat/delegating_class'
28
+ extend DelegatingClass
29
+ @delegates_to = ::Chef::Resource::ActionClass
30
+ end
31
+ #
32
+ # If load_current_value! is defined on the resource, use that.
33
+ #
34
+ def load_current_resource
35
+ if new_resource.respond_to?(:load_current_value!)
36
+ # dup the resource and then reset desired-state properties.
37
+ current_resource = new_resource.dup
38
+
39
+ # We clear desired state in the copy, because it is supposed to be actual state.
40
+ # We keep identity properties and non-desired-state, which are assumed to be
41
+ # "control" values like `recurse: true`
42
+ current_resource.class.properties.each do |name,property|
43
+ if property.desired_state? && !property.identity? && !property.name_property?
44
+ property.reset(current_resource)
45
+ end
46
+ end
47
+
48
+ # Call the actual load_current_value! method. If it raises
49
+ # CurrentValueDoesNotExist, set current_resource to `nil`.
50
+ begin
51
+ # If the user specifies load_current_value do |desired_resource|, we
52
+ # pass in the desired resource as well as the current one.
53
+ if current_resource.method(:load_current_value!).arity > 0
54
+ current_resource.load_current_value!(new_resource)
55
+ else
56
+ current_resource.load_current_value!
57
+ end
58
+ rescue Chef::Exceptions::CurrentValueDoesNotExist
59
+ current_resource = nil
60
+ end
61
+ end
62
+
63
+ @current_resource = current_resource
64
+ end
65
+
66
+ def self.included(other)
67
+ other.extend(ClassMethods)
68
+ other.use_inline_resources
69
+ other.include_resource_dsl true
70
+ end
71
+
72
+ module ClassMethods
73
+ if defined?(::Chef::Resource::ActionClass::ClassMethods)
74
+ require 'chef_compat/delegating_class'
75
+ extend DelegatingClass
76
+ @delegates_to = ::Chef::Resource::ActionClass::ClassMethods
77
+ end
78
+ #
79
+ # The Chef::Resource class this ActionClass was declared against.
80
+ #
81
+ # @return [Class] The Chef::Resource class this ActionClass was declared against.
82
+ #
83
+ attr_accessor :resource_class
84
+
85
+ def to_s
86
+ "#{resource_class} action provider"
87
+ end
88
+
89
+ def inspect
90
+ to_s
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end