puppet-resource_api 1.6.2 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 306133cd86d46867056bd6bf220111b843d0edae82af69e3e428aba627377f56
4
- data.tar.gz: 7652de8fdc6c86124994ba0b66d78a403baa779eb4b27ed2de0f1862cb7867be
3
+ metadata.gz: 5c84f42dbe3cadd9471c1a763bf3981e998bf285df618970ee4b09d5218d3603
4
+ data.tar.gz: 4575e26e85ee7c52ba389480ccd1348001e48396657fd7dcacc9f074c7ccf0fd
5
5
  SHA512:
6
- metadata.gz: 45dd940aa1b6cd7aa5378fb2a401158dbb482c6d3171925bcb2ad3a68ed2e017dff6738c6d40c4ee061a6f25a2b4ba582c480ef103a7ebda041f3a7d5ca9657f
7
- data.tar.gz: 725ee6aeb23a0ad23905b5f6e39c2d66d24461976a6318d35db4bd0839d70314f743e84cefa4ca63cfe11b8f49099b1a2f9a6a1d4bae987826b95f9545c8a75b
6
+ metadata.gz: 042a05622f752fb21487292a296fdaa45ef5b468248a513473698834dd20c4129331f69734cb86f0bf22a410dbddefa41e253d3fdd610edf227937961d398154
7
+ data.tar.gz: 73092a426db653e4b7311684ec6ced636884cf9605c18ce84f99fe697f069dcd5894448feea1f3d1b27c94fd220f33008835efcb76b636ff7429377ac8d0f87c
@@ -1,7 +1,12 @@
1
1
  require 'pathname'
2
+ require 'puppet/resource_api/data_type_handling'
2
3
  require 'puppet/resource_api/glue'
4
+ require 'puppet/resource_api/parameter'
5
+ require 'puppet/resource_api/property'
3
6
  require 'puppet/resource_api/puppet_context' unless RUBY_PLATFORM == 'java'
7
+ require 'puppet/resource_api/read_only_parameter'
4
8
  require 'puppet/resource_api/type_definition'
9
+ require 'puppet/resource_api/value_creator'
5
10
  require 'puppet/resource_api/version'
6
11
  require 'puppet/type'
7
12
  require 'puppet/util/network_device'
@@ -25,7 +30,7 @@ module Puppet::ResourceApi
25
30
  raise Puppet::DevError, '`:title_patterns` must be an array, not `%{other_type}`' % { other_type: definition[:title_patterns].class }
26
31
  end
27
32
 
28
- validate_ensure(definition)
33
+ Puppet::ResourceApi::DataTypeHandling.validate_ensure(definition)
29
34
 
30
35
  definition[:features] ||= []
31
36
  supported_features = %w[supports_noop canonicalize remote_resource simple_get_filter].freeze
@@ -137,7 +142,10 @@ module Puppet::ResourceApi
137
142
  return if @ral_find_absent
138
143
 
139
144
  definition[:attributes].each do |name, options|
140
- type = Puppet::ResourceApi.parse_puppet_type(:name, options[:type])
145
+ type = Puppet::ResourceApi::DataTypeHandling.parse_puppet_type(
146
+ :name,
147
+ options[:type],
148
+ )
141
149
 
142
150
  # skip read only vars and the namevar
143
151
  next if [:read_only, :namevar].include? options[:behaviour]
@@ -170,13 +178,23 @@ module Puppet::ResourceApi
170
178
  # TODO: using newparam everywhere would suppress change reporting
171
179
  # that would allow more fine-grained reporting through context,
172
180
  # but require more invest in hooking up the infrastructure to emulate existing data
173
- param_or_property = if [:read_only, :parameter, :namevar].include? options[:behaviour]
174
- :newparam
175
- else
176
- :newproperty
177
- end
181
+ if [:parameter, :namevar].include? options[:behaviour]
182
+ param_or_property = :newparam
183
+ parent = Puppet::ResourceApi::Parameter
184
+ elsif options[:behaviour] == :read_only
185
+ param_or_property = :newparam
186
+ parent = Puppet::ResourceApi::ReadOnlyParameter
187
+ else
188
+ param_or_property = :newproperty
189
+ parent = Puppet::ResourceApi::Property
190
+ end
178
191
 
179
- send(param_or_property, name.to_sym) do
192
+ # This call creates a new parameter or property with all work-arounds or
193
+ # customizations required by the Resource API applied. Under the hood,
194
+ # this maps to the relevant DSL methods in Puppet::Type. See
195
+ # https://puppet.com/docs/puppet/6.0/custom_types.html#reference-5883
196
+ # for details.
197
+ send(param_or_property, name.to_sym, parent: parent) do
180
198
  unless options[:type]
181
199
  raise Puppet::DevError, "#{definition[:name]}.#{name} has no type"
182
200
  end
@@ -187,129 +205,32 @@ module Puppet::ResourceApi
187
205
  warn("#{definition[:name]}.#{name} has no docs")
188
206
  end
189
207
 
190
- if options[:behaviour] == :namevar
191
- isnamevar
192
- end
193
-
194
- # read-only values do not need type checking, but can have default values
195
- if options[:behaviour] != :read_only && options.key?(:default)
196
- if options.key? :default
197
- if options[:default] == false
198
- # work around https://tickets.puppetlabs.com/browse/PUP-2368
199
- defaultto :false # rubocop:disable Lint/BooleanSymbol
200
- elsif options[:default] == true
201
- # work around https://tickets.puppetlabs.com/browse/PUP-2368
202
- defaultto :true # rubocop:disable Lint/BooleanSymbol
203
- else
204
- # marshal the default option to decouple that from the actual value.
205
- # we cache the dumped value in `marshalled`, but use a block to unmarshal
206
- # everytime the value is requested. Objects that can't be marshalled
207
- # See https://stackoverflow.com/a/8206537/4918
208
- marshalled = Marshal.dump(options[:default])
209
- defaultto { Marshal.load(marshalled) } # rubocop:disable Security/MarshalLoad
210
- end
211
- end
212
- end
213
-
214
- if name == :ensure
215
- def insync?(is)
216
- rs_value.to_s == is.to_s
217
- end
218
- end
219
-
220
- type = Puppet::ResourceApi.parse_puppet_type(name, options[:type])
221
-
222
- if param_or_property == :newproperty
223
- define_method(:should) do
224
- if name == :ensure && rs_value.is_a?(String)
225
- rs_value.to_sym
226
- elsif rs_value == false
227
- # work around https://tickets.puppetlabs.com/browse/PUP-2368
228
- :false # rubocop:disable Lint/BooleanSymbol
229
- elsif rs_value == true
230
- # work around https://tickets.puppetlabs.com/browse/PUP-2368
231
- :true # rubocop:disable Lint/BooleanSymbol
232
- else
233
- rs_value
234
- end
235
- end
236
-
237
- define_method(:should=) do |value|
238
- @shouldorig = value
239
-
240
- if name == :ensure
241
- value = value.to_s
242
- end
243
-
244
- # Puppet requires the @should value to always be stored as an array. We do not use this
245
- # for anything else
246
- # @see Puppet::Property.should=(value)
247
- @should = [Puppet::ResourceApi.mungify(type, value, "#{definition[:name]}.#{name}")]
248
- end
249
-
250
- # used internally
251
- # @returns the final mungified value of this property
252
- define_method(:rs_value) do
253
- @should ? @should.first : @should
254
- end
255
- else
256
- define_method(:value) do
257
- @value
258
- end
259
-
260
- define_method(:value=) do |value|
261
- if options[:behaviour] == :read_only
262
- raise Puppet::ResourceError, "Attempting to set `#{name}` read_only attribute value to `#{value}`"
263
- end
264
-
265
- @value = Puppet::ResourceApi.mungify(type, value, "#{definition[:name]}.#{name}")
266
- end
267
-
268
- # used internally
269
- # @returns the final mungified value of this parameter
270
- define_method(:rs_value) do
271
- @value
272
- end
273
- end
274
-
275
- # puppet symbolizes some values through puppet/parameter/value.rb (see .convert()), but (especially) Enums
276
- # are strings. specifying a munge block here skips the value_collection fallback in puppet/parameter.rb's
277
- # default .unsafe_munge() implementation.
278
- munge { |v| v }
279
-
280
- # provide hints to `puppet type generate` for better parsing
281
- if type.instance_of? Puppet::Pops::Types::POptionalType
282
- type = type.type
283
- end
284
-
285
- case type
286
- when Puppet::Pops::Types::PStringType
287
- # require any string value
288
- Puppet::ResourceApi.def_newvalues(self, param_or_property, %r{})
289
- when Puppet::Pops::Types::PBooleanType
290
- Puppet::ResourceApi.def_newvalues(self, param_or_property, 'true', 'false')
291
- aliasvalue true, 'true'
292
- aliasvalue false, 'false'
293
- aliasvalue :true, 'true' # rubocop:disable Lint/BooleanSymbol
294
- aliasvalue :false, 'false' # rubocop:disable Lint/BooleanSymbol
295
-
296
- when Puppet::Pops::Types::PIntegerType
297
- Puppet::ResourceApi.def_newvalues(self, param_or_property, %r{^-?\d+$})
298
- when Puppet::Pops::Types::PFloatType, Puppet::Pops::Types::PNumericType
299
- Puppet::ResourceApi.def_newvalues(self, param_or_property, Puppet::Pops::Patterns::NUMERIC)
208
+ # The initialize method is called when puppet core starts building up
209
+ # type objects. The core passes in a hash of shape { resource:
210
+ # #<Puppet::Type::TypeName> }. We use this to pass through the
211
+ # required configuration data to the parent (see
212
+ # Puppet::ResourceApi::Property, Puppet::ResourceApi::Parameter and
213
+ # Puppet::ResourceApi::ReadOnlyParameter).
214
+ define_method(:initialize) do |resource_hash|
215
+ super(definition[:name], self.class.data_type, name, resource_hash)
300
216
  end
301
217
 
302
- if param_or_property == :newproperty
303
- # stop puppet from trying to call into the provider when
304
- # no pre-defined values have been specified
305
- # "This is not the provider you are looking for." -- Obi-Wan Kaniesobi.
306
- def call_provider(value); end
218
+ # get pops data type object for this parameter or property
219
+ define_singleton_method(:data_type) do
220
+ @rsapi_data_type ||= Puppet::ResourceApi::DataTypeHandling.parse_puppet_type(
221
+ name,
222
+ options[:type],
223
+ )
307
224
  end
308
225
 
309
- case options[:type]
310
- when 'Enum[present, absent]'
311
- Puppet::ResourceApi.def_newvalues(self, param_or_property, 'absent', 'present')
312
- end
226
+ # from ValueCreator call create_values which makes alias values and
227
+ # default values for properties and params
228
+ Puppet::ResourceApi::ValueCreator.create_values(
229
+ self,
230
+ data_type,
231
+ param_or_property,
232
+ options,
233
+ )
313
234
  end
314
235
  end
315
236
 
@@ -563,162 +484,7 @@ MESSAGE
563
484
  type_name.to_s.split('_').map(&:capitalize).join
564
485
  end
565
486
 
566
- # Add the value to `this` property or param, depending on whether param_or_property is `:newparam`, or `:newproperty`
567
- def self.def_newvalues(this, param_or_property, *values)
568
- if param_or_property == :newparam
569
- this.newvalues(*values)
570
- else
571
- values.each do |v|
572
- this.newvalue(v) {}
573
- end
574
- end
575
- end
576
-
577
487
  def self.caller_is_resource_app?
578
488
  caller.any? { |c| c.match(%r{application/resource.rb:}) }
579
489
  end
580
-
581
- # This method handles translating values from the runtime environment to the expected types for the provider.
582
- # When being called from `puppet resource`, it tries to transform the strings from the command line into their
583
- # expected ruby representations, e.g. `"2"` (a string), will be transformed to `2` (the number) if (and only if)
584
- # the target `type` is `Integer`.
585
- # Additionally this function also validates that the passed in (and optionally transformed) value matches the
586
- # specified type.
587
- # @param type[Puppet::Pops::Types::TypedModelObject] the type to check/clean against
588
- # @param value the value to clean
589
- # @param error_msg_prefix[String] a prefix for the error messages
590
- # @return [type] the cleaned value
591
- # @raise [Puppet::ResourceError] if `value` could not be parsed into `type`
592
- def self.mungify(type, value, error_msg_prefix)
593
- if caller_is_resource_app?
594
- # When the provider is exercised from the `puppet resource` CLI, we need to unpack strings into
595
- # the correct types, e.g. "1" (a string) to 1 (an integer)
596
- cleaned_value, error_msg = try_mungify(type, value, error_msg_prefix)
597
- raise Puppet::ResourceError, error_msg if error_msg
598
- elsif value == :false # rubocop:disable Lint/BooleanSymbol
599
- # work around https://tickets.puppetlabs.com/browse/PUP-2368
600
- cleaned_value = false
601
- elsif value == :true # rubocop:disable Lint/BooleanSymbol
602
- # work around https://tickets.puppetlabs.com/browse/PUP-2368
603
- cleaned_value = true
604
- else
605
- # Every other time, we can use the values as is
606
- cleaned_value = value
607
- end
608
- Puppet::ResourceApi.validate(type, cleaned_value, error_msg_prefix)
609
- cleaned_value
610
- end
611
-
612
- # Recursive implementation part of #mungify. Uses a multi-valued return value to avoid excessive
613
- # exception throwing for regular usage
614
- # @return [Array] if the mungify worked, the first element is the cleaned value, and the second
615
- # element is nil. If the mungify failed, the first element is nil, and the second element is an error
616
- # message
617
- # @private
618
- def self.try_mungify(type, value, error_msg_prefix)
619
- case type
620
- when Puppet::Pops::Types::PArrayType
621
- if value.is_a? Array
622
- conversions = value.map do |v|
623
- try_mungify(type.element_type, v, error_msg_prefix)
624
- end
625
- # only convert the values if none failed. otherwise fall through and rely on puppet to render a proper error
626
- if conversions.all? { |c| c[1].nil? }
627
- value = conversions.map { |c| c[0] }
628
- end
629
- end
630
- when Puppet::Pops::Types::PBooleanType
631
- value = case value
632
- when 'true', :true # rubocop:disable Lint/BooleanSymbol
633
- true
634
- when 'false', :false # rubocop:disable Lint/BooleanSymbol
635
- false
636
- else
637
- value
638
- end
639
- when Puppet::Pops::Types::PIntegerType, Puppet::Pops::Types::PFloatType, Puppet::Pops::Types::PNumericType
640
- if value =~ %r{^-?\d+$} || value =~ Puppet::Pops::Patterns::NUMERIC
641
- value = Puppet::Pops::Utils.to_n(value)
642
- end
643
- when Puppet::Pops::Types::PEnumType, Puppet::Pops::Types::PStringType, Puppet::Pops::Types::PPatternType
644
- if value.is_a? Symbol
645
- value = value.to_s
646
- end
647
- when Puppet::Pops::Types::POptionalType
648
- return value.nil? ? [nil, nil] : try_mungify(type.type, value, error_msg_prefix)
649
- when Puppet::Pops::Types::PVariantType
650
- # try converting to anything except string first
651
- string_type = type.types.find { |t| t.is_a? Puppet::Pops::Types::PStringType }
652
- conversion_results = (type.types - [string_type]).map do |t|
653
- try_mungify(t, value, error_msg_prefix)
654
- end
655
-
656
- # only consider valid results
657
- conversion_results = conversion_results.select { |r| r[1].nil? }.to_a
658
-
659
- # use the conversion result if unambiguous
660
- return conversion_results[0] if conversion_results.length == 1
661
-
662
- # return an error if ambiguous
663
- return [nil, "#{error_msg_prefix} #{value.inspect} is not unabiguously convertable to #{type}"] if conversion_results.length > 1
664
-
665
- # try to interpret as string
666
- return try_mungify(string_type, value, error_msg_prefix) if string_type
667
-
668
- # fall through to default handling
669
- end
670
-
671
- error_msg = try_validate(type, value, error_msg_prefix)
672
- if error_msg
673
- # an error :-(
674
- [nil, error_msg]
675
- else
676
- # a match!
677
- [value, nil]
678
- end
679
- end
680
-
681
- # Validates the `value` against the specified `type`.
682
- # @param type[Puppet::Pops::Types::TypedModelObject] the type to check against
683
- # @param value the value to clean
684
- # @param error_msg_prefix[String] a prefix for the error messages
685
- # @raise [Puppet::ResourceError] if `value` is not of type `type`
686
- # @private
687
- def self.validate(type, value, error_msg_prefix)
688
- error_msg = try_validate(type, value, error_msg_prefix)
689
-
690
- raise Puppet::ResourceError, error_msg if error_msg
691
- end
692
-
693
- # Tries to validate the `value` against the specified `type`.
694
- # @param type[Puppet::Pops::Types::TypedModelObject] the type to check against
695
- # @param value the value to clean
696
- # @param error_msg_prefix[String] a prefix for the error messages
697
- # @return [String, nil] a error message indicating the problem, or `nil` if the value was valid.
698
- # @private
699
- def self.try_validate(type, value, error_msg_prefix)
700
- return nil if type.instance?(value)
701
-
702
- # an error :-(
703
- inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value)
704
- error_msg = Puppet::Pops::Types::TypeMismatchDescriber.new.describe_mismatch(error_msg_prefix, type, inferred_type)
705
- error_msg
706
- end
707
-
708
- def self.validate_ensure(definition)
709
- return unless definition[:attributes].key? :ensure
710
- options = definition[:attributes][:ensure]
711
- type = Puppet::ResourceApi.parse_puppet_type(:ensure, options[:type])
712
-
713
- return if type.is_a?(Puppet::Pops::Types::PEnumType) && type.values.sort == %w[absent present].sort
714
- raise Puppet::DevError, '`:ensure` attribute must have a type of: `Enum[present, absent]`'
715
- end
716
-
717
- def self.parse_puppet_type(attr_name, type)
718
- Puppet::Pops::Types::TypeParser.singleton.parse(type)
719
- rescue Puppet::ParseErrorWithIssue => e
720
- raise Puppet::DevError, "The type of the `#{attr_name}` attribute `#{type}` could not be parsed: #{e.message}"
721
- rescue Puppet::ParseError => e
722
- raise Puppet::DevError, "The type of the `#{attr_name}` attribute `#{type}` is not recognised: #{e.message}"
723
- end
724
490
  end
@@ -0,0 +1,198 @@
1
+ module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation,Style/ClassAndModuleChildren
2
+
3
+ # This module is used to handle data inside types, contains methods for munging
4
+ # and validation of the type values.
5
+ module Puppet::ResourceApi::DataTypeHandling
6
+ # This method handles translating values from the runtime environment to the
7
+ # expected types for the provider with validation.
8
+ # When being called from `puppet resource`, it tries to transform the strings
9
+ # from the command line into their expected ruby representations,
10
+ # e.g. `"2"` (a string), will be transformed to `2` (the number)
11
+ # if (and only if) the target `type` is `Integer`.
12
+ # Additionally this function also validates that the passed in
13
+ # (and optionally transformed) value matches the specified type.
14
+ # @param type[Puppet::Pops::Types::TypedModelObject] the type to check/clean
15
+ # against.
16
+ # @param value the value to clean
17
+ # @param error_msg_prefix[String] a prefix for the error messages
18
+ # @param unpack_strings[Boolean] unpacking of strings for migrating off
19
+ # legacy type
20
+ # @return [type] the cleaned value
21
+ def self.mungify(type, value, error_msg_prefix, unpack_strings = false)
22
+ cleaned_value = mungify_core(
23
+ type,
24
+ value,
25
+ error_msg_prefix,
26
+ unpack_strings,
27
+ )
28
+ validate(type, cleaned_value, error_msg_prefix)
29
+ cleaned_value
30
+ end
31
+
32
+ # This is core method used in mungify which handles translating values to expected
33
+ # cleaned type values, result is not validated.
34
+ # @param type[Puppet::Pops::Types::TypedModelObject] the type to check/clean
35
+ # against.
36
+ # @param value the value to clean
37
+ # @param error_msg_prefix[String] a prefix for the error messages
38
+ # @param unpack_strings[Boolean] unpacking of strings for migrating off
39
+ # legacy type
40
+ # @return [type] the cleaned value
41
+ # @raise [Puppet::ResourceError] if `value` could not be parsed into `type`
42
+ # @private
43
+ def self.mungify_core(type, value, error_msg_prefix, unpack_strings = false)
44
+ if unpack_strings
45
+ # When the provider is exercised from the `puppet resource` CLI, we need
46
+ # to unpack strings into the correct types, e.g. "1" (a string)
47
+ # to 1 (an integer)
48
+ cleaned_value, error_msg = try_mungify(type, value, error_msg_prefix)
49
+ raise Puppet::ResourceError, error_msg if error_msg
50
+ cleaned_value
51
+ elsif value == :false # rubocop:disable Lint/BooleanSymbol
52
+ # work around https://tickets.puppetlabs.com/browse/PUP-2368
53
+ false
54
+ elsif value == :true # rubocop:disable Lint/BooleanSymbol
55
+ # work around https://tickets.puppetlabs.com/browse/PUP-2368
56
+ true
57
+ else
58
+ # Every other time, we can use the values as is
59
+ value
60
+ end
61
+ end
62
+
63
+ # Recursive implementation part of #mungify_core. Uses a multi-valued return
64
+ # value to avoid excessive exception throwing for regular usage.
65
+ # @return [Array] if the mungify worked, the first element is the cleaned
66
+ # value, and the second element is nil. If the mungify failed, the first
67
+ # element is nil, and the second element is an error message
68
+ # @private
69
+ def self.try_mungify(type, value, error_msg_prefix)
70
+ case type
71
+ when Puppet::Pops::Types::PArrayType
72
+ if value.is_a? Array
73
+ conversions = value.map do |v|
74
+ try_mungify(type.element_type, v, error_msg_prefix)
75
+ end
76
+ # only convert the values if none failed. otherwise fall through and
77
+ # rely on puppet to render a proper error
78
+ if conversions.all? { |c| c[1].nil? }
79
+ value = conversions.map { |c| c[0] }
80
+ end
81
+ end
82
+ when Puppet::Pops::Types::PBooleanType
83
+ value = boolean_munge(value)
84
+ when Puppet::Pops::Types::PIntegerType,
85
+ Puppet::Pops::Types::PFloatType,
86
+ Puppet::Pops::Types::PNumericType
87
+ if value =~ %r{^-?\d+$} || value =~ Puppet::Pops::Patterns::NUMERIC
88
+ value = Puppet::Pops::Utils.to_n(value)
89
+ end
90
+ when Puppet::Pops::Types::PEnumType,
91
+ Puppet::Pops::Types::PStringType,
92
+ Puppet::Pops::Types::PPatternType
93
+ value = value.to_s if value.is_a? Symbol
94
+ when Puppet::Pops::Types::POptionalType
95
+ return value.nil? ? [nil, nil] : try_mungify(type.type, value, error_msg_prefix)
96
+ when Puppet::Pops::Types::PVariantType
97
+ # try converting to anything except string first
98
+ string_type = type.types.find { |t| t.is_a? Puppet::Pops::Types::PStringType }
99
+ conversion_results = (type.types - [string_type]).map do |t|
100
+ try_mungify(t, value, error_msg_prefix)
101
+ end
102
+
103
+ # only consider valid results
104
+ conversion_results = conversion_results.select { |r| r[1].nil? }.to_a
105
+
106
+ # use the conversion result if unambiguous
107
+ return conversion_results[0] if conversion_results.length == 1
108
+
109
+ # return an error if ambiguous
110
+ if conversion_results.length > 1
111
+ return [nil, ambiguous_error_msg(error_msg_prefix, value, type)]
112
+ end
113
+
114
+ # try to interpret as string
115
+ return try_mungify(string_type, value, error_msg_prefix) if string_type
116
+
117
+ # fall through to default handling
118
+ end
119
+
120
+ error_msg = try_validate(type, value, error_msg_prefix)
121
+ return [nil, error_msg] if error_msg # an error
122
+ [value, nil] # match
123
+ end
124
+
125
+ # Returns correct boolean `value` based on one specified in `type`.
126
+ # @param value the value to boolean munge
127
+ # @private
128
+ def self.boolean_munge(value)
129
+ case value
130
+ when 'true', :true # rubocop:disable Lint/BooleanSymbol
131
+ true
132
+ when 'false', :false # rubocop:disable Lint/BooleanSymbol
133
+ false
134
+ else
135
+ value
136
+ end
137
+ end
138
+
139
+ # Returns ambiguous error message based on `error_msg_prefix`, `value` and
140
+ # `type`.
141
+ # @param type[Puppet::Pops::Types::TypedModelObject] the type to check against
142
+ # @param value the value to clean
143
+ # @param error_msg_prefix[String] a prefix for the error messages
144
+ # @private
145
+ def self.ambiguous_error_msg(error_msg_prefix, value, type)
146
+ "#{error_msg_prefix} #{value.inspect} is not unabiguously convertable to " \
147
+ "#{type}"
148
+ end
149
+
150
+ # Validates the `value` against the specified `type`.
151
+ # @param type[Puppet::Pops::Types::TypedModelObject] the type to check against
152
+ # @param value the value to clean
153
+ # @param error_msg_prefix[String] a prefix for the error messages
154
+ # @raise [Puppet::ResourceError] if `value` is not of type `type`
155
+ # @private
156
+ def self.validate(type, value, error_msg_prefix)
157
+ error_msg = try_validate(type, value, error_msg_prefix)
158
+ raise Puppet::ResourceError, error_msg if error_msg
159
+ end
160
+
161
+ # Tries to validate the `value` against the specified `type`.
162
+ # @param type[Puppet::Pops::Types::TypedModelObject] the type to check against
163
+ # @param value the value to clean
164
+ # @param error_msg_prefix[String] a prefix for the error messages
165
+ # @return [String, nil] a error message indicating the problem, or `nil` if the value was valid.
166
+ # @private
167
+ def self.try_validate(type, value, error_msg_prefix)
168
+ return nil if type.instance?(value)
169
+
170
+ # an error :-(
171
+ inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value)
172
+ error_msg = Puppet::Pops::Types::TypeMismatchDescriber.new.describe_mismatch(
173
+ error_msg_prefix,
174
+ type,
175
+ inferred_type,
176
+ )
177
+ error_msg
178
+ end
179
+
180
+ def self.validate_ensure(definition)
181
+ return unless definition[:attributes].key? :ensure
182
+ options = definition[:attributes][:ensure]
183
+ type = parse_puppet_type(:ensure, options[:type])
184
+
185
+ return if type.is_a?(Puppet::Pops::Types::PEnumType) && type.values.sort == %w[absent present].sort
186
+ raise Puppet::DevError, '`:ensure` attribute must have a type of: `Enum[present, absent]`'
187
+ end
188
+
189
+ def self.parse_puppet_type(attr_name, type)
190
+ Puppet::Pops::Types::TypeParser.singleton.parse(type)
191
+ rescue Puppet::ParseErrorWithIssue => e
192
+ raise Puppet::DevError, "The type of the `#{attr_name}` attribute " \
193
+ "`#{type}` could not be parsed: #{e.message}"
194
+ rescue Puppet::ParseError => e
195
+ raise Puppet::DevError, "The type of the `#{attr_name}` attribute " \
196
+ "`#{type}` is not recognised: #{e.message}"
197
+ end
198
+ end
@@ -0,0 +1,46 @@
1
+ require 'puppet/util'
2
+ require 'puppet/parameter'
3
+
4
+ module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation,Style/ClassAndModuleChildren
5
+
6
+ # Class containing parameter functionality for ResourceApi.
7
+ class Puppet::ResourceApi::Parameter < Puppet::Parameter
8
+ attr_reader :value
9
+
10
+ # This initialize takes arguments and sets up new parameter.
11
+ # @param type_name the name of the Puppet Type
12
+ # @param data_type the data type of parameter instance
13
+ # @param attribute_name the name of attribue of the parameter
14
+ # @param resource_hash the resource hash instance which is passed to the
15
+ # parent class.
16
+ def initialize(type_name, data_type, attribute_name, resource_hash)
17
+ @type_name = type_name
18
+ @data_type = data_type
19
+ @attribute_name = attribute_name
20
+ super(resource_hash) # Pass resource to parent Puppet class.
21
+ end
22
+
23
+ # This method assigns value to the parameter and cleans value.
24
+ # @param value the value to be set and clean
25
+ # @return [type] the cleaned value
26
+ def value=(value)
27
+ @value = Puppet::ResourceApi::DataTypeHandling.mungify(
28
+ @data_type,
29
+ value,
30
+ "#{@type_name}.#{@attribute_name}",
31
+ Puppet::ResourceApi.caller_is_resource_app?,
32
+ )
33
+ end
34
+
35
+ # used internally
36
+ # @returns the final mungified value of this parameter
37
+ def rs_value
38
+ @value
39
+ end
40
+
41
+ # puppet symbolizes some values through puppet/parameter/value.rb
42
+ # (see .convert()), but (especially) Enums are strings. specifying a
43
+ # munge block here skips the value_collection fallback in
44
+ # puppet/parameter.rb's default .unsafe_munge() implementation.
45
+ munge { |v| v }
46
+ end
@@ -0,0 +1,86 @@
1
+ require 'puppet/util'
2
+ require 'puppet/property'
3
+
4
+ module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation,Style/ClassAndModuleChildren
5
+
6
+ # Class containing property functionality for ResourceApi.
7
+ class Puppet::ResourceApi::Property < Puppet::Property
8
+ # This initialize takes arguments and sets up new property.
9
+ # @param type_name the name of the Puppet Type
10
+ # @param data_type the data type of property instance
11
+ # @param attribute_name the name of attribue of the property
12
+ # @param resource_hash the resource hash instance which is passed to the
13
+ # parent class.
14
+ def initialize(type_name, data_type, attribute_name, resource_hash)
15
+ @type_name = type_name
16
+ @data_type = data_type
17
+ @attribute_name = attribute_name
18
+ # Define class method insync?(is) if the name is :ensure
19
+ def_insync? if @attribute_name == :ensure && self.class != Puppet::ResourceApi::Property
20
+ # Pass resource to parent Puppet class.
21
+ super(resource_hash)
22
+ end
23
+
24
+ # This method returns value of the property.
25
+ # @return [type] the property value
26
+ def should
27
+ if @attribute_name == :ensure && rs_value.is_a?(String)
28
+ rs_value.to_sym
29
+ elsif rs_value == false
30
+ # work around https://tickets.puppetlabs.com/browse/PUP-2368
31
+ :false # rubocop:disable Lint/BooleanSymbol
32
+ elsif rs_value == true
33
+ # work around https://tickets.puppetlabs.com/browse/PUP-2368
34
+ :true # rubocop:disable Lint/BooleanSymbol
35
+ else
36
+ rs_value
37
+ end
38
+ end
39
+
40
+ # This method sets and returns value of the property and sets @shouldorig.
41
+ # @param value the value to be set and clean
42
+ # @return [type] the property value
43
+ def should=(value)
44
+ @shouldorig = value
45
+
46
+ if @attribute_name == :ensure
47
+ value = value.to_s
48
+ end
49
+
50
+ # Puppet requires the @should value to always be stored as an array. We do not use this
51
+ # for anything else
52
+ # @see Puppet::Property.should=(value)
53
+ @should = [
54
+ Puppet::ResourceApi::DataTypeHandling.mungify(
55
+ @data_type,
56
+ value,
57
+ "#{@type_name}.#{@attribute_name}",
58
+ Puppet::ResourceApi.caller_is_resource_app?,
59
+ ),
60
+ ]
61
+ end
62
+
63
+ # used internally
64
+ # @returns the final mungified value of this property
65
+ def rs_value
66
+ @should ? @should.first : @should
67
+ end
68
+
69
+ # method overloaded only for the :ensure property, add option to check if the
70
+ # rs_value matches is. Only if the class is child of
71
+ # Puppet::ResourceApi::Property.
72
+ def def_insync?
73
+ define_singleton_method(:insync?) { |is| rs_value.to_s == is.to_s }
74
+ end
75
+
76
+ # puppet symbolizes some values through puppet/parameter/value.rb
77
+ # (see .convert()), but (especially) Enums are strings. specifying a
78
+ # munge block here skips the value_collection fallback in
79
+ # puppet/parameter.rb's default .unsafe_munge() implementation.
80
+ munge { |v| v }
81
+
82
+ # stop puppet from trying to call into the provider when
83
+ # no pre-defined values have been specified
84
+ # "This is not the provider you are looking for." -- Obi-Wan Kaniesobi.
85
+ def call_provider(_value); end
86
+ end
@@ -0,0 +1,19 @@
1
+ require 'puppet/util'
2
+ require 'puppet/resource_api/parameter'
3
+
4
+ # Class containing read only parameter functionality for ResourceApi.
5
+ class Puppet::ResourceApi::ReadOnlyParameter < Puppet::ResourceApi::Parameter
6
+ # This method raises error if the there is attempt to set value in parameter.
7
+ # @return [Puppet::ResourceError] the error with information.
8
+ def value=(value)
9
+ raise Puppet::ResourceError,
10
+ "Attempting to set `#{@attribute_name}` read_only attribute value " \
11
+ "to `#{value}`"
12
+ end
13
+
14
+ # used internally
15
+ # @returns the final mungified value of this parameter
16
+ def rs_value
17
+ @value
18
+ end
19
+ end
@@ -84,8 +84,15 @@ class Puppet::ResourceApi::TypeDefinition
84
84
  bad_vals = {}
85
85
  resource.each do |key, value|
86
86
  next unless attributes[key]
87
- type = Puppet::ResourceApi.parse_puppet_type(key, attributes[key][:type])
88
- error_message = Puppet::ResourceApi.try_validate(type, value, '')
87
+ type = Puppet::ResourceApi::DataTypeHandling.parse_puppet_type(
88
+ key,
89
+ attributes[key][:type],
90
+ )
91
+ error_message = Puppet::ResourceApi::DataTypeHandling.try_validate(
92
+ type,
93
+ value,
94
+ '',
95
+ )
89
96
  bad_vals[key] = value unless error_message.nil?
90
97
  end
91
98
  bad_vals
@@ -0,0 +1,75 @@
1
+ module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation,Style/ClassAndModuleChildren
2
+
3
+ # This module is responsible for setting default and alias values for the
4
+ # resource class.
5
+ module Puppet::ResourceApi::ValueCreator
6
+ # This method is responsible for all setup of the value mapping for desired
7
+ # resource class which can be Puppet::ResourceApi::Parameter,
8
+ # Puppet::ResourceApi::ReadOnlyParameter, Puppet::ResourceApi::Property.
9
+ # @param resource_class the class of selected resource to be extended
10
+ # @param data_type the type instance
11
+ # @param definition the definition of the property
12
+ # @param options the ResourceAPI options hash containing setup information for
13
+ # selected parameter or property
14
+ def self.create_values(attribute_class, data_type, param_or_property, options = {})
15
+ attribute_class.isnamevar if options[:behaviour] == :namevar
16
+
17
+ # read-only values do not need type checking, but can have default values
18
+ if options[:behaviour] != :read_only && options.key?(:default)
19
+ if options[:default] == false
20
+ # work around https://tickets.puppetlabs.com/browse/PUP-2368
21
+ attribute_class.defaultto :false # rubocop:disable Lint/BooleanSymbol
22
+ elsif options[:default] == true
23
+ # work around https://tickets.puppetlabs.com/browse/PUP-2368
24
+ attribute_class.defaultto :true # rubocop:disable Lint/BooleanSymbol
25
+ else
26
+ # marshal the default option to decouple that from the actual value.
27
+ # we cache the dumped value in `marshalled`, but use a block to
28
+ # unmarshal everytime the value is requested. Objects that can't be
29
+ # marshalled
30
+ # See https://stackoverflow.com/a/8206537/4918
31
+ marshalled = Marshal.dump(options[:default])
32
+ attribute_class.defaultto { Marshal.load(marshalled) } # rubocop:disable Security/MarshalLoad
33
+ end
34
+ end
35
+
36
+ # provide hints to `puppet type generate` for better parsing
37
+ if data_type.instance_of? Puppet::Pops::Types::POptionalType
38
+ data_type = data_type.type
39
+ end
40
+
41
+ case data_type
42
+ when Puppet::Pops::Types::PStringType
43
+ # require any string value
44
+ def_newvalues(attribute_class, param_or_property, %r{})
45
+ when Puppet::Pops::Types::PBooleanType
46
+ def_newvalues(attribute_class, param_or_property, 'true', 'false')
47
+ attribute_class.aliasvalue true, 'true'
48
+ attribute_class.aliasvalue false, 'false'
49
+ attribute_class.aliasvalue :true, 'true' # rubocop:disable Lint/BooleanSymbol
50
+ attribute_class.aliasvalue :false, 'false' # rubocop:disable Lint/BooleanSymbol
51
+ when Puppet::Pops::Types::PIntegerType
52
+ def_newvalues(attribute_class, param_or_property, %r{^-?\d+$})
53
+ when Puppet::Pops::Types::PFloatType, Puppet::Pops::Types::PNumericType
54
+ def_newvalues(attribute_class, param_or_property, Puppet::Pops::Patterns::NUMERIC)
55
+ end
56
+
57
+ case options[:type]
58
+ when 'Enum[present, absent]'
59
+ def_newvalues(attribute_class, param_or_property, 'absent', 'present')
60
+ end
61
+ attribute_class
62
+ end
63
+
64
+ # add the value to `this` property or param, depending on whether
65
+ # param_or_property is `:newparam`, or `:newproperty`
66
+ def self.def_newvalues(this, param_or_property, *values)
67
+ if param_or_property == :newparam
68
+ this.newvalues(*values)
69
+ else
70
+ values.each do |v|
71
+ this.newvalue(v) {}
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,5 +1,5 @@
1
1
  module Puppet
2
2
  module ResourceApi
3
- VERSION = '1.6.2'.freeze
3
+ VERSION = '1.6.3'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-resource_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Schmitt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-25 00:00:00.000000000 Z
11
+ date: 2019-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hocon
@@ -53,11 +53,16 @@ files:
53
53
  - contrib/pre-commit
54
54
  - lib/puppet/resource_api.rb
55
55
  - lib/puppet/resource_api/base_context.rb
56
+ - lib/puppet/resource_api/data_type_handling.rb
56
57
  - lib/puppet/resource_api/glue.rb
57
58
  - lib/puppet/resource_api/io_context.rb
59
+ - lib/puppet/resource_api/parameter.rb
60
+ - lib/puppet/resource_api/property.rb
58
61
  - lib/puppet/resource_api/puppet_context.rb
62
+ - lib/puppet/resource_api/read_only_parameter.rb
59
63
  - lib/puppet/resource_api/simple_provider.rb
60
64
  - lib/puppet/resource_api/type_definition.rb
65
+ - lib/puppet/resource_api/value_creator.rb
61
66
  - lib/puppet/resource_api/version.rb
62
67
  - lib/puppet/util/network_device/simple/device.rb
63
68
  - misc/ANNOUNCEMENT_TEMPLATE.md
@@ -82,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
87
  version: '0'
83
88
  requirements: []
84
89
  rubyforge_project:
85
- rubygems_version: 2.7.6
90
+ rubygems_version: 2.7.6.2
86
91
  signing_key:
87
92
  specification_version: 4
88
93
  summary: This library provides a simple way to write new native resources for puppet.