Skip to content

Commit 969d88c

Browse files
authored
Merge pull request #146 from da-ar/register_transport
(FM-7597) RSAPI Transport register function
2 parents ec20021 + c69083d commit 969d88c

File tree

8 files changed

+512
-310
lines changed

8 files changed

+512
-310
lines changed

lib/puppet/resource_api.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require 'puppet/resource_api/property'
66
require 'puppet/resource_api/puppet_context' unless RUBY_PLATFORM == 'java'
77
require 'puppet/resource_api/read_only_parameter'
8+
require 'puppet/resource_api/transport'
89
require 'puppet/resource_api/type_definition'
910
require 'puppet/resource_api/value_creator'
1011
require 'puppet/resource_api/version'
@@ -451,6 +452,12 @@ def load_device_provider(class_name, type_name_sym, device_class_name, device_na
451452
end
452453
module_function :load_device_provider # rubocop:disable Style/AccessModifierDeclarations
453454

455+
# keeps the existing register API format. e.g. Puppet::ResourceApi.register_type
456+
def register_transport(schema)
457+
Puppet::ResourceApi::Transport.register(schema)
458+
end
459+
module_function :register_transport # rubocop:disable Style/AccessModifierDeclarations
460+
454461
def self.class_name_from_type_name(type_name)
455462
type_name.to_s.split('_').map(&:capitalize).join
456463
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Remote target transport API
2+
module Puppet::ResourceApi::Transport
3+
def register(schema)
4+
raise Puppet::DevError, 'requires a hash as schema, not `%{other_type}`' % { other_type: schema.class } unless schema.is_a? Hash
5+
raise Puppet::DevError, 'requires a `:name`' unless schema.key? :name
6+
raise Puppet::DevError, 'requires `:desc`' unless schema.key? :desc
7+
raise Puppet::DevError, 'requires `:connection_info`' unless schema.key? :connection_info
8+
raise Puppet::DevError, '`:connection_info` must be a hash, not `%{other_type}`' % { other_type: schema[:connection_info].class } unless schema[:connection_info].is_a?(Hash)
9+
10+
@transports ||= {}
11+
raise Puppet::DevError, 'Transport `%{name}` is already registered.' % { name: schema[:name] } unless @transports[schema[:name]].nil?
12+
@transports[schema[:name]] = Puppet::ResourceApi::TransportSchemaDef.new(schema)
13+
end
14+
module_function :register # rubocop:disable Style/AccessModifierDeclarations
15+
end
Lines changed: 137 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,168 @@
11
# Provides accessor methods for the type being provided
2-
class Puppet::ResourceApi::TypeDefinition
3-
attr_reader :definition
2+
module Puppet::ResourceApi
3+
# pre-declare class
4+
class BaseTypeDefinition; end
5+
6+
# RSAPI Resource Type
7+
class TypeDefinition < BaseTypeDefinition
8+
def initialize(definition)
9+
super(definition, :attributes)
10+
end
411

5-
def initialize(definition)
6-
@data_type_cache = {}
7-
validate_schema(definition)
8-
end
12+
def ensurable?
13+
attributes.key?(:ensure)
14+
end
915

10-
def name
11-
@definition[:name]
12-
end
16+
# rubocop complains when this is named has_feature?
17+
def feature?(feature)
18+
supported = (definition[:features] && definition[:features].include?(feature))
19+
if supported
20+
Puppet.debug("#{definition[:name]} supports `#{feature}`")
21+
else
22+
Puppet.debug("#{definition[:name]} does not support `#{feature}`")
23+
end
24+
supported
25+
end
1326

14-
def attributes
15-
@definition[:attributes]
16-
end
27+
def validate_schema(definition, attr_key)
28+
super(definition, attr_key)
29+
[:title, :provider, :alias, :audit, :before, :consume, :export, :loglevel, :noop, :notify, :require, :schedule, :stage, :subscribe, :tag].each do |name|
30+
raise Puppet::DevError, 'must not define an attribute called `%{name}`' % { name: name.inspect } if definition[attr_key].key? name
31+
end
32+
if definition.key?(:title_patterns) && !definition[:title_patterns].is_a?(Array)
33+
raise Puppet::DevError, '`:title_patterns` must be an array, not `%{other_type}`' % { other_type: definition[:title_patterns].class }
34+
end
1735

18-
def ensurable?
19-
@definition[:attributes].key?(:ensure)
20-
end
36+
Puppet::ResourceApi::DataTypeHandling.validate_ensure(definition)
2137

22-
def namevars
23-
@namevars ||= @definition[:attributes].select { |_name, options|
24-
options.key?(:behaviour) && options[:behaviour] == :namevar
25-
}.keys
26-
end
38+
definition[:features] ||= []
39+
supported_features = %w[supports_noop canonicalize remote_resource simple_get_filter].freeze
40+
unknown_features = definition[:features] - supported_features
41+
Puppet.warning("Unknown feature detected: #{unknown_features.inspect}") unless unknown_features.empty?
2742

28-
# rubocop complains when this is named has_feature?
29-
def feature?(feature)
30-
supported = (definition[:features] && definition[:features].include?(feature))
31-
if supported
32-
Puppet.debug("#{definition[:name]} supports `#{feature}`")
33-
else
34-
Puppet.debug("#{definition[:name]} does not support `#{feature}`")
43+
# store the validated definition
44+
@definition = definition
3545
end
36-
supported
3746
end
3847

39-
def validate_schema(definition)
40-
raise Puppet::DevError, 'Type definition must be a Hash, not `%{other_type}`' % { other_type: definition.class } unless definition.is_a?(Hash)
41-
raise Puppet::DevError, 'Type definition must have a name' unless definition.key? :name
42-
raise Puppet::DevError, 'Type definition must have `:attributes`' unless definition.key? :attributes
43-
unless definition[:attributes].is_a?(Hash)
44-
raise Puppet::DevError, '`%{name}.attributes` must be a hash, not `%{other_type}`' % {
45-
name: definition[:name], other_type: definition[:attributes].class
46-
}
47-
end
48-
[:title, :provider, :alias, :audit, :before, :consume, :export, :loglevel, :noop, :notify, :require, :schedule, :stage, :subscribe, :tag].each do |name|
49-
raise Puppet::DevError, 'must not define an attribute called `%{name}`' % { name: name.inspect } if definition[:attributes].key? name
50-
end
51-
if definition.key?(:title_patterns) && !definition[:title_patterns].is_a?(Array)
52-
raise Puppet::DevError, '`:title_patterns` must be an array, not `%{other_type}`' % { other_type: definition[:title_patterns].class }
48+
# RSAPI Transport schema
49+
class TransportSchemaDef < BaseTypeDefinition
50+
def initialize(definition)
51+
super(definition, :connection_info)
5352
end
53+
end
5454

55-
Puppet::ResourceApi::DataTypeHandling.validate_ensure(definition)
55+
# Base RSAPI schema Object
56+
class BaseTypeDefinition
57+
attr_reader :definition, :attributes
58+
59+
def initialize(definition, attr_key)
60+
@data_type_cache = {}
61+
validate_schema(definition, attr_key)
62+
end
5663

57-
definition[:features] ||= []
58-
supported_features = %w[supports_noop canonicalize remote_resource simple_get_filter].freeze
59-
unknown_features = definition[:features] - supported_features
60-
Puppet.warning("Unknown feature detected: #{unknown_features.inspect}") unless unknown_features.empty?
64+
def name
65+
@definition[:name]
66+
end
6167

62-
definition[:attributes].each do |key, attr|
63-
raise Puppet::DevError, "`#{definition[:name]}.#{key}` must be a Hash, not a #{attr.class}" unless attr.is_a? Hash
64-
raise Puppet::DevError, "`#{definition[:name]}.#{key}` has no type" unless attr.key? :type
65-
Puppet.warning("`#{definition[:name]}.#{key}` has no docs") unless attr.key? :desc
68+
def namevars
69+
@namevars ||= attributes.select { |_name, options|
70+
options.key?(:behaviour) && options[:behaviour] == :namevar
71+
}.keys
72+
end
6673

67-
# validate the type by attempting to parse into a puppet type
68-
@data_type_cache[definition[:attributes][key][:type]] ||=
69-
Puppet::ResourceApi::DataTypeHandling.parse_puppet_type(
70-
key,
71-
definition[:attributes][key][:type],
72-
)
74+
def validate_schema(definition, attr_key)
75+
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)
76+
@attributes = definition[attr_key]
77+
raise Puppet::DevError, '%{type_class} must have a name' % { type_class: self.class.name } unless definition.key? :name
78+
raise Puppet::DevError, '%{type_class} must have `%{attr_key}`' % { type_class: self.class.name, attrs: attr_key } unless definition.key? attr_key
79+
unless attributes.is_a?(Hash)
80+
raise Puppet::DevError, '`%{name}.%{attrs}` must be a hash, not `%{other_type}`' % {
81+
name: definition[:name], attrs: attr_key, other_type: attributes.class
82+
}
83+
end
7384

74-
# fixup any weird behavior ;-)
75-
next unless attr[:behavior]
76-
if attr[:behaviour]
77-
raise Puppet::DevError, "the '#{key}' attribute has both a `behavior` and a `behaviour`, only use one"
85+
attributes.each do |key, attr|
86+
raise Puppet::DevError, "`#{definition[:name]}.#{key}` must be a Hash, not a #{attr.class}" unless attr.is_a? Hash
87+
raise Puppet::DevError, "`#{definition[:name]}.#{key}` has no type" unless attr.key? :type
88+
Puppet.warning("`#{definition[:name]}.#{key}` has no docs") unless attr.key? :desc
89+
90+
# validate the type by attempting to parse into a puppet type
91+
@data_type_cache[attributes[key][:type]] ||=
92+
Puppet::ResourceApi::DataTypeHandling.parse_puppet_type(
93+
key,
94+
attributes[key][:type],
95+
)
96+
97+
# fixup any weird behavior ;-)
98+
next unless attr[:behavior]
99+
if attr[:behaviour]
100+
raise Puppet::DevError, "the '#{key}' attribute has both a `behavior` and a `behaviour`, only use one"
101+
end
102+
attr[:behaviour] = attr[:behavior]
103+
attr.delete(:behavior)
78104
end
79-
attr[:behaviour] = attr[:behavior]
80-
attr.delete(:behavior)
105+
# store the validated definition
106+
@definition = definition
81107
end
82-
# store the validated definition
83-
@definition = definition
84-
end
85108

86-
# validates a resource hash against its type schema
87-
def check_schema(resource)
88-
namevars.each do |namevar|
89-
if resource[namevar].nil?
90-
raise Puppet::ResourceError, "`#{name}.get` did not return a value for the `#{namevar}` namevar attribute"
109+
# validates a resource hash against its type schema
110+
def check_schema(resource)
111+
namevars.each do |namevar|
112+
if resource[namevar].nil?
113+
raise Puppet::ResourceError, "`#{name}.get` did not return a value for the `#{namevar}` namevar attribute"
114+
end
91115
end
92-
end
93116

94-
message = "Provider returned data that does not match the Type Schema for `#{name}[#{resource[namevars.first]}]`"
117+
message = "Provider returned data that does not match the Type Schema for `#{name}[#{resource[namevars.first]}]`"
95118

96-
rejected_keys = check_schema_keys(resource) # removes bad keys
97-
bad_values = check_schema_values(resource)
119+
rejected_keys = check_schema_keys(resource) # removes bad keys
120+
bad_values = check_schema_values(resource)
98121

99-
unless rejected_keys.empty?
100-
message += "\n Unknown attribute:\n"
101-
rejected_keys.each { |key, _value| message += " * #{key}\n" }
102-
end
103-
unless bad_values.empty?
104-
message += "\n Value type mismatch:\n"
105-
bad_values.each { |key, value| message += " * #{key}: #{value}\n" }
106-
end
122+
unless rejected_keys.empty?
123+
message += "\n Unknown attribute:\n"
124+
rejected_keys.each { |key, _value| message += " * #{key}\n" }
125+
end
126+
unless bad_values.empty?
127+
message += "\n Value type mismatch:\n"
128+
bad_values.each { |key, value| message += " * #{key}: #{value}\n" }
129+
end
107130

108-
return if rejected_keys.empty? && bad_values.empty?
131+
return if rejected_keys.empty? && bad_values.empty?
109132

110-
if Puppet.settings[:strict] == :off
111-
Puppet.debug(message)
112-
elsif Puppet.settings[:strict] == :warning
113-
Puppet::ResourceApi.warning_count += 1
114-
Puppet.warning(message) if Puppet::ResourceApi.warning_count <= 100 # maximum number of schema warnings to display in a run
115-
elsif Puppet.settings[:strict] == :error
116-
raise Puppet::DevError, message
133+
if Puppet.settings[:strict] == :off
134+
Puppet.debug(message)
135+
elsif Puppet.settings[:strict] == :warning
136+
Puppet::ResourceApi.warning_count += 1
137+
Puppet.warning(message) if Puppet::ResourceApi.warning_count <= 100 # maximum number of schema warnings to display in a run
138+
elsif Puppet.settings[:strict] == :error
139+
raise Puppet::DevError, message
140+
end
117141
end
118-
end
119142

120-
# Returns an array of keys that where not found in the type schema
121-
# Modifies the resource passed in, leaving only valid attributes
122-
def check_schema_keys(resource)
123-
rejected = []
124-
resource.reject! { |key| rejected << key if key != :title && attributes.key?(key) == false }
125-
rejected
126-
end
143+
# Returns an array of keys that where not found in the type schema
144+
# Modifies the resource passed in, leaving only valid attributes
145+
def check_schema_keys(resource)
146+
rejected = []
147+
resource.reject! { |key| rejected << key if key != :title && attributes.key?(key) == false }
148+
rejected
149+
end
127150

128-
# Returns a hash of keys and values that are not valid
129-
# does not modify the resource passed in
130-
def check_schema_values(resource)
131-
bad_vals = {}
132-
resource.each do |key, value|
133-
next unless attributes[key]
134-
type = @data_type_cache[attributes[key][:type]]
135-
error_message = Puppet::ResourceApi::DataTypeHandling.try_validate(
136-
type,
137-
value,
138-
'',
139-
)
140-
bad_vals[key] = value unless error_message.nil?
151+
# Returns a hash of keys and values that are not valid
152+
# does not modify the resource passed in
153+
def check_schema_values(resource)
154+
bad_vals = {}
155+
resource.each do |key, value|
156+
next unless attributes[key]
157+
type = @data_type_cache[attributes[key][:type]]
158+
error_message = Puppet::ResourceApi::DataTypeHandling.try_validate(
159+
type,
160+
value,
161+
'',
162+
)
163+
bad_vals[key] = value unless error_message.nil?
164+
end
165+
bad_vals
141166
end
142-
bad_vals
143167
end
144168
end

0 commit comments

Comments
 (0)