compat_resource 12.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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