puppet-resource_api 1.6.2 → 1.6.3

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.
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.