puppet-resource_api 1.8.9 → 1.8.14

Sign up to get free protection for your applications and to get access to all the features.
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.