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 +4 -4
- data/lib/puppet/resource_api.rb +48 -282
- data/lib/puppet/resource_api/data_type_handling.rb +198 -0
- data/lib/puppet/resource_api/parameter.rb +46 -0
- data/lib/puppet/resource_api/property.rb +86 -0
- data/lib/puppet/resource_api/read_only_parameter.rb +19 -0
- data/lib/puppet/resource_api/type_definition.rb +9 -2
- data/lib/puppet/resource_api/value_creator.rb +75 -0
- data/lib/puppet/resource_api/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c84f42dbe3cadd9471c1a763bf3981e998bf285df618970ee4b09d5218d3603
|
4
|
+
data.tar.gz: 4575e26e85ee7c52ba389480ccd1348001e48396657fd7dcacc9f074c7ccf0fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 042a05622f752fb21487292a296fdaa45ef5b468248a513473698834dd20c4129331f69734cb86f0bf22a410dbddefa41e253d3fdd610edf227937961d398154
|
7
|
+
data.tar.gz: 73092a426db653e4b7311684ec6ced636884cf9605c18ce84f99fe697f069dcd5894448feea1f3d1b27c94fd220f33008835efcb76b636ff7429377ac8d0f87c
|
data/lib/puppet/resource_api.rb
CHANGED
@@ -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(
|
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
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
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
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
#
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
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(
|
88
|
-
|
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
|
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.
|
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:
|
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.
|