puppet-resource_api 1.8.9 → 1.8.14

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.dependency_decisions.yml +9 -9
  3. data/.github/dependabot.yml +12 -0
  4. data/.rubocop.yml +1 -1
  5. data/.travis.yml +12 -48
  6. data/CHANGELOG.md +138 -24
  7. data/Gemfile +39 -17
  8. data/HISTORY.md +0 -5
  9. data/README.md +6 -6
  10. data/appveyor.yml +3 -3
  11. data/contrib/pre-commit +2 -0
  12. data/docs/README.md +7 -0
  13. data/docs/hands-on-lab/01-installing-prereqs.md +16 -0
  14. data/docs/hands-on-lab/02-connecting-to-the-lightbulbs-emulator.png +0 -0
  15. data/docs/hands-on-lab/02-connecting-to-the-lightbulbs.md +26 -0
  16. data/docs/hands-on-lab/03-creating-a-new-module.md +47 -0
  17. data/docs/hands-on-lab/03-creating-a-new-module_vscode.png +0 -0
  18. data/docs/hands-on-lab/04-adding-a-new-transport.md +123 -0
  19. data/docs/hands-on-lab/05-implementing-the-transport-hints.md +19 -0
  20. data/docs/hands-on-lab/05-implementing-the-transport.md +126 -0
  21. data/docs/hands-on-lab/06-implementing-the-provider.md +227 -0
  22. data/docs/hands-on-lab/07-implementing-a-task.md +181 -0
  23. data/lib/puppet/resource_api.rb +95 -55
  24. data/lib/puppet/resource_api/base_context.rb +6 -0
  25. data/lib/puppet/resource_api/data_type_handling.rb +2 -0
  26. data/lib/puppet/resource_api/glue.rb +9 -2
  27. data/lib/puppet/resource_api/io_context.rb +2 -0
  28. data/lib/puppet/resource_api/parameter.rb +4 -2
  29. data/lib/puppet/resource_api/property.rb +65 -5
  30. data/lib/puppet/resource_api/puppet_context.rb +2 -0
  31. data/lib/puppet/resource_api/read_only_parameter.rb +2 -0
  32. data/lib/puppet/resource_api/simple_provider.rb +2 -0
  33. data/lib/puppet/resource_api/transport.rb +2 -0
  34. data/lib/puppet/resource_api/transport/wrapper.rb +2 -0
  35. data/lib/puppet/resource_api/type_definition.rb +63 -3
  36. data/lib/puppet/resource_api/value_creator.rb +2 -0
  37. data/lib/puppet/resource_api/version.rb +3 -1
  38. data/lib/puppet/util/network_device/simple/device.rb +2 -0
  39. metadata +15 -4
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet/resource_api/base_context'
2
4
 
3
5
  # Implement Resource API Conext to log through an IO object, defaulting to `$stderr`.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet/util'
2
4
  require 'puppet/parameter'
3
5
 
@@ -13,11 +15,11 @@ class Puppet::ResourceApi::Parameter < Puppet::Parameter
13
15
  # @param attribute_name the name of attribue of the parameter
14
16
  # @param resource_hash the resource hash instance which is passed to the
15
17
  # parent class.
16
- def initialize(type_name, data_type, attribute_name, resource_hash)
18
+ def initialize(type_name, data_type, attribute_name, resource_hash, _referrable_type = nil)
17
19
  @type_name = type_name
18
20
  @data_type = data_type
19
21
  @attribute_name = attribute_name
20
- super(resource_hash) # Pass resource to parent Puppet class.
22
+ super(**resource_hash) # Pass resource to parent Puppet class.
21
23
  end
22
24
 
23
25
  # This method assigns value to the parameter and cleans value.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet/util'
2
4
  require 'puppet/property'
3
5
 
@@ -11,14 +13,31 @@ class Puppet::ResourceApi::Property < Puppet::Property
11
13
  # @param attribute_name the name of attribue of the property
12
14
  # @param resource_hash the resource hash instance which is passed to the
13
15
  # parent class.
14
- def initialize(type_name, data_type, attribute_name, resource_hash)
16
+ def initialize(type_name, data_type, attribute_name, resource_hash, referrable_type = nil)
15
17
  @type_name = type_name
16
18
  @data_type = data_type
17
19
  @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
+ @resource = resource_hash[:resource]
21
+ @referrable_type = referrable_type
22
+
23
+ # Do not want to define insync on the base class because
24
+ # this overrides for everything instead of only for the
25
+ # appropriate instance/class of the property.
26
+ if self.class != Puppet::ResourceApi::Property
27
+ # Define class method insync?(is) if the custom_insync feature flag is set
28
+ if referrable_type&.type_definition&.feature?('custom_insync')
29
+ def_custom_insync?
30
+ if @attribute_name == :rsapi_custom_insync_trigger
31
+ @change_to_s_value = 'Custom insync logic determined that this resource is out of sync'
32
+ end
33
+ # Define class method insync?(is) if the name is :ensure and custom_insync feature flag is not set
34
+ elsif @attribute_name == :ensure
35
+ def_ensure_insync?
36
+ end
37
+ end
38
+
20
39
  # Pass resource to parent Puppet class.
21
- super(resource_hash)
40
+ super(**resource_hash)
22
41
  end
23
42
 
24
43
  # This method returns value of the property.
@@ -69,10 +88,51 @@ class Puppet::ResourceApi::Property < Puppet::Property
69
88
  # method overloaded only for the :ensure property, add option to check if the
70
89
  # rs_value matches is. Only if the class is child of
71
90
  # Puppet::ResourceApi::Property.
72
- def def_insync?
91
+ def def_ensure_insync?
73
92
  define_singleton_method(:insync?) { |is| rs_value.to_s == is.to_s }
74
93
  end
75
94
 
95
+ def def_custom_insync?
96
+ define_singleton_method(:insync?) do |is|
97
+ provider = @referrable_type.my_provider
98
+ context = @referrable_type.context
99
+ should_hash = @resource.rsapi_canonicalized_target_state
100
+ is_hash = @resource.rsapi_current_state
101
+ title = @resource.rsapi_title
102
+
103
+ raise(Puppet::DevError, 'No insync? method defined in the provider; an insync? method must be defined if the custom_insync feature is defined for the type') unless provider.respond_to?(:insync?)
104
+
105
+ provider_insync_result, change_message = provider.insync?(context, title, @attribute_name, is_hash, should_hash)
106
+
107
+ unless provider_insync_result.nil? || change_message.nil? || change_message.empty?
108
+ @change_to_s_value = change_message
109
+ end
110
+
111
+ case provider_insync_result
112
+ when nil
113
+ # If validating ensure and no custom insync was used, check if rs_value matches is.
114
+ return rs_value.to_s == is.to_s if @attribute_name == :ensure
115
+ # Otherwise, super and rely on Puppet::Property.insync?
116
+ super(is)
117
+ when TrueClass, FalseClass
118
+ return provider_insync_result
119
+ else
120
+ # When returning anything else, raise a DevError for a non-idiomatic return
121
+ raise(Puppet::DevError, "Custom insync for #{@attribute_name} returned a #{provider_insync_result.class} with a value of #{provider_insync_result.inspect} instead of true/false; insync? MUST return nil or the boolean true or false") # rubocop:disable Metrics/LineLength
122
+ end
123
+ end
124
+
125
+ define_singleton_method(:change_to_s) do |current_value, newvalue|
126
+ # As defined in the custom insync? method, it is sometimes useful to overwrite the default change messaging;
127
+ # The enables a user to return a more useful change report than a strict "is to should" report.
128
+ # If @change_to_s_value is not set, Puppet writes a generic change notification, like:
129
+ # Notice: /Stage[main]/Main/<type_name>[<name_hash>]/<property name>: <property name> changed <is value> to <should value>
130
+ # If #change_to_s_value is *nil* Puppet writes a weird empty message like:
131
+ # Notice: /Stage[main]/Main/<type_name>[<name_hash>]/<property name>:
132
+ @change_to_s_value || super(current_value, newvalue)
133
+ end
134
+ end
135
+
76
136
  # puppet symbolizes some values through puppet/parameter/value.rb
77
137
  # (see .convert()), but (especially) Enums are strings. specifying a
78
138
  # munge block here skips the value_collection fallback in
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet/resource_api/base_context'
2
4
  require 'puppet/util/logging'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet/util'
2
4
  require 'puppet/resource_api/parameter'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puppet; end # rubocop:disable Style/Documentation
2
4
 
3
5
  module Puppet::ResourceApi
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puppet::ResourceApi; end # rubocop:disable Style/Documentation
2
4
 
3
5
  # Remote target transport API
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet/resource_api/transport'
2
4
  require 'hocon'
3
5
  require 'hocon/config_syntax'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Provides accessor methods for the type being provided
2
4
  module Puppet::ResourceApi
3
5
  # pre-declare class
@@ -15,7 +17,11 @@ module Puppet::ResourceApi
15
17
 
16
18
  # rubocop complains when this is named has_feature?
17
19
  def feature?(feature)
18
- (definition[:features] && definition[:features].include?(feature))
20
+ definition[:features]&.include?(feature)
21
+ end
22
+
23
+ def title_patterns
24
+ definition[:title_patterns] ||= []
19
25
  end
20
26
 
21
27
  def validate_schema(definition, attr_key)
@@ -30,10 +36,56 @@ module Puppet::ResourceApi
30
36
  Puppet::ResourceApi::DataTypeHandling.validate_ensure(definition)
31
37
 
32
38
  definition[:features] ||= []
33
- supported_features = %w[supports_noop canonicalize remote_resource simple_get_filter].freeze
39
+ supported_features = %w[supports_noop canonicalize custom_insync remote_resource simple_get_filter].freeze
34
40
  unknown_features = definition[:features] - supported_features
35
41
  Puppet.warning("Unknown feature detected: #{unknown_features.inspect}") unless unknown_features.empty?
36
42
  end
43
+
44
+ # This call creates a new parameter or property with all work-arounds or
45
+ # customizations required by the Resource API applied. Under the hood,
46
+ # this maps to the relevant DSL methods in Puppet::Type. See
47
+ # https://puppet.com/docs/puppet/6.0/custom_types.html#reference-5883
48
+ # for details.
49
+ #
50
+ # type: the Resource API Type the attribute is being created in
51
+ # attribute_name: the name of the attribute being created
52
+ # param_or_property: Whether to call the :newparam or :newproperty method
53
+ # parent: The type of attribute to create: Property, ReadOnly, or Parameter
54
+ # options: The hash of attribute options, including type, desc, default, and behaviour
55
+ def create_attribute_in(type, attribute_name, param_or_property, parent, options)
56
+ type.send(param_or_property, attribute_name.to_sym, parent: parent) do
57
+ if options[:desc]
58
+ desc "#{options[:desc]} (a #{options[:type]})"
59
+ end
60
+
61
+ # The initialize method is called when puppet core starts building up
62
+ # type objects. The core passes in a hash of shape { resource:
63
+ # #<Puppet::Type::TypeName> }. We use this to pass through the
64
+ # required configuration data to the parent (see
65
+ # Puppet::ResourceApi::Property, Puppet::ResourceApi::Parameter and
66
+ # Puppet::ResourceApi::ReadOnlyParameter).
67
+ define_method(:initialize) do |resource_hash|
68
+ super(type.name, self.class.data_type, attribute_name, resource_hash, type)
69
+ end
70
+
71
+ # get pops data type object for this parameter or property
72
+ define_singleton_method(:data_type) do
73
+ @rsapi_data_type ||= Puppet::ResourceApi::DataTypeHandling.parse_puppet_type(
74
+ attribute_name,
75
+ options[:type],
76
+ )
77
+ end
78
+
79
+ # from ValueCreator call create_values which makes alias values and
80
+ # default values for properties and params
81
+ Puppet::ResourceApi::ValueCreator.create_values(
82
+ self,
83
+ data_type,
84
+ param_or_property,
85
+ options,
86
+ )
87
+ end
88
+ end
37
89
  end
38
90
 
39
91
  # RSAPI Transport schema
@@ -84,6 +136,13 @@ module Puppet::ResourceApi
84
136
  }.keys
85
137
  end
86
138
 
139
+ def insyncable_attributes
140
+ @insyncable_attributes ||= attributes.reject { |_name, options|
141
+ # Only attributes without any behavior are normal Puppet Properties and get insynced
142
+ options.key?(:behaviour)
143
+ }.keys
144
+ end
145
+
87
146
  def validate_schema(definition, attr_key)
88
147
  raise Puppet::DevError, '%{type_class} must be a Hash, not `%{other_type}`' % { type_class: self.class.name, other_type: definition.class } unless definition.is_a?(Hash)
89
148
  @attributes = definition[attr_key]
@@ -106,6 +165,7 @@ module Puppet::ResourceApi
106
165
  Puppet.warning('`%{name}` has no documentation, add it using a `desc` key' % { name: definition[:name] }) unless definition.key? :desc
107
166
 
108
167
  attributes.each do |key, attr|
168
+ raise Puppet::DevError, '`rsapi_custom_insync_trigger` cannot be specified as an attribute; it is reserved for propertyless types with the custom_insync feature' if key == :rsapi_custom_insync_trigger # rubocop:disable Metrics/LineLength
109
169
  raise Puppet::DevError, "`#{definition[:name]}.#{key}` must be a Hash, not a #{attr.class}" unless attr.is_a? Hash
110
170
  raise Puppet::DevError, "`#{definition[:name]}.#{key}` has no type" unless attr.key? :type
111
171
  Puppet.warning('`%{name}.%{key}` has no documentation, add it using a `desc` key' % { name: definition[:name], key: key }) unless attr.key? :desc
@@ -190,7 +250,7 @@ module Puppet::ResourceApi
190
250
  if is_sensitive
191
251
  bad_vals[key] = '<< redacted value >> ' + error_message unless error_message.nil?
192
252
  else
193
- bad_vals[key] = value unless error_message.nil?
253
+ bad_vals[key] = "#{value} (#{error_message})" unless error_message.nil?
194
254
  end
195
255
  end
196
256
  bad_vals
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation,Style/ClassAndModuleChildren
2
4
 
3
5
  # This module is responsible for setting default and alias values for the
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puppet
2
4
  module ResourceApi
3
- VERSION = '1.8.9'.freeze
5
+ VERSION = '1.8.14'
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'hocon'
2
4
  require 'hocon/config_syntax'
3
5
 
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.8.9
4
+ version: 1.8.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Schmitt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-02-19 00:00:00.000000000 Z
11
+ date: 2021-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hocon
@@ -33,6 +33,7 @@ extra_rdoc_files: []
33
33
  files:
34
34
  - ".dependency_decisions.yml"
35
35
  - ".fixtures.yml"
36
+ - ".github/dependabot.yml"
36
37
  - ".gitignore"
37
38
  - ".rspec"
38
39
  - ".rubocop.yml"
@@ -52,6 +53,17 @@ files:
52
53
  - codecov.yml
53
54
  - contrib/README.md
54
55
  - contrib/pre-commit
56
+ - docs/README.md
57
+ - docs/hands-on-lab/01-installing-prereqs.md
58
+ - docs/hands-on-lab/02-connecting-to-the-lightbulbs-emulator.png
59
+ - docs/hands-on-lab/02-connecting-to-the-lightbulbs.md
60
+ - docs/hands-on-lab/03-creating-a-new-module.md
61
+ - docs/hands-on-lab/03-creating-a-new-module_vscode.png
62
+ - docs/hands-on-lab/04-adding-a-new-transport.md
63
+ - docs/hands-on-lab/05-implementing-the-transport-hints.md
64
+ - docs/hands-on-lab/05-implementing-the-transport.md
65
+ - docs/hands-on-lab/06-implementing-the-provider.md
66
+ - docs/hands-on-lab/07-implementing-a-task.md
55
67
  - lib/puppet/resource_api.rb
56
68
  - lib/puppet/resource_api/base_context.rb
57
69
  - lib/puppet/resource_api/data_type_handling.rb
@@ -88,8 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
100
  - !ruby/object:Gem::Version
89
101
  version: '0'
90
102
  requirements: []
91
- rubyforge_project:
92
- rubygems_version: 2.7.6.2
103
+ rubygems_version: 3.2.5
93
104
  signing_key:
94
105
  specification_version: 4
95
106
  summary: This library provides a simple way to write new native resources for puppet.