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