puppet-resource_api 1.9.2 → 2.0.1
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/CHANGELOG.md +378 -414
- data/lib/puppet/resource_api/base_context.rb +11 -7
- data/lib/puppet/resource_api/data_type_handling.rb +15 -19
- data/lib/puppet/resource_api/glue.rb +4 -7
- data/lib/puppet/resource_api/parameter.rb +2 -2
- data/lib/puppet/resource_api/property.rb +9 -14
- data/lib/puppet/resource_api/provider_get_cache.rb +41 -0
- data/lib/puppet/resource_api/puppet_context.rb +1 -0
- data/lib/puppet/resource_api/simple_provider.rb +19 -19
- data/lib/puppet/resource_api/transport/wrapper.rb +5 -3
- data/lib/puppet/resource_api/transport.rb +24 -31
- data/lib/puppet/resource_api/type_definition.rb +38 -45
- data/lib/puppet/resource_api/value_creator.rb +4 -6
- data/lib/puppet/resource_api/version.rb +1 -1
- data/lib/puppet/resource_api.rb +120 -90
- data/lib/puppet/util/network_device/simple/device.rb +2 -0
- metadata +8 -3
|
@@ -19,7 +19,7 @@ class Puppet::ResourceApi::BaseContext
|
|
|
19
19
|
elsif definition.is_a? Puppet::ResourceApi::BaseTypeDefinition
|
|
20
20
|
@type = definition
|
|
21
21
|
else
|
|
22
|
-
raise ArgumentError, 'BaseContext requires definition to be a child of Puppet::ResourceApi::BaseTypeDefinition, not
|
|
22
|
+
raise ArgumentError, format('BaseContext requires definition to be a child of Puppet::ResourceApi::BaseTypeDefinition, not <%<actual_type>s>', actual_type: definition.class)
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -44,7 +44,7 @@ class Puppet::ResourceApi::BaseContext
|
|
|
44
44
|
type.feature?(feature)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
[
|
|
47
|
+
%i[debug info notice warning err].each do |level|
|
|
48
48
|
define_method(level) do |*args|
|
|
49
49
|
if args.length == 1
|
|
50
50
|
message = "#{@context || @type.name}: #{args.last}"
|
|
@@ -58,7 +58,7 @@ class Puppet::ResourceApi::BaseContext
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
[
|
|
61
|
+
%i[creating updating deleting].each do |method|
|
|
62
62
|
define_method(method) do |titles, message: method.to_s.capitalize, &block|
|
|
63
63
|
start_time = Time.now
|
|
64
64
|
setup_context(titles, message)
|
|
@@ -92,6 +92,7 @@ class Puppet::ResourceApi::BaseContext
|
|
|
92
92
|
|
|
93
93
|
def processing(title, is, should, message = 'Processing')
|
|
94
94
|
raise "#{__method__} only accepts a single resource title" if title.respond_to?(:each)
|
|
95
|
+
|
|
95
96
|
start_time = Time.now
|
|
96
97
|
setup_context(title, message)
|
|
97
98
|
begin
|
|
@@ -106,7 +107,7 @@ class Puppet::ResourceApi::BaseContext
|
|
|
106
107
|
end
|
|
107
108
|
end
|
|
108
109
|
|
|
109
|
-
[
|
|
110
|
+
%i[created updated deleted].each do |method|
|
|
110
111
|
define_method(method) do |titles, message: method.to_s.capitalize|
|
|
111
112
|
notice("#{message}: #{titles}")
|
|
112
113
|
end
|
|
@@ -114,11 +115,13 @@ class Puppet::ResourceApi::BaseContext
|
|
|
114
115
|
|
|
115
116
|
def processed(title, is, should)
|
|
116
117
|
raise "#{__method__} only accepts a single resource title" if title.respond_to?(:each)
|
|
118
|
+
|
|
117
119
|
notice("Processed #{title} from #{is} to #{should}")
|
|
118
120
|
end
|
|
119
121
|
|
|
120
122
|
def attribute_changed(title, attribute, is, should, message: nil)
|
|
121
123
|
raise "#{__method__} only accepts a single resource title" if title.respond_to?(:each)
|
|
124
|
+
|
|
122
125
|
printable_is = 'nil'
|
|
123
126
|
printable_should = 'nil'
|
|
124
127
|
if is
|
|
@@ -156,7 +159,7 @@ class Puppet::ResourceApi::BaseContext
|
|
|
156
159
|
private
|
|
157
160
|
|
|
158
161
|
def format_titles(titles)
|
|
159
|
-
if titles.
|
|
162
|
+
if titles.empty? && !titles.is_a?(String)
|
|
160
163
|
@type.name
|
|
161
164
|
else
|
|
162
165
|
"#{@type.name}[#{[titles].flatten.compact.join(', ')}]"
|
|
@@ -169,7 +172,8 @@ class Puppet::ResourceApi::BaseContext
|
|
|
169
172
|
end
|
|
170
173
|
|
|
171
174
|
def format_seconds(seconds)
|
|
172
|
-
return '%.6f'
|
|
173
|
-
|
|
175
|
+
return format('%.6f', seconds) if seconds < 1
|
|
176
|
+
|
|
177
|
+
format('%.2f', seconds)
|
|
174
178
|
end
|
|
175
179
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation
|
|
3
|
+
module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation
|
|
4
4
|
|
|
5
5
|
# This module is used to handle data inside types, contains methods for munging
|
|
6
6
|
# and validation of the type values.
|
|
@@ -20,12 +20,12 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
20
20
|
# @param unpack_strings[Boolean] unpacking of strings for migrating off
|
|
21
21
|
# legacy type
|
|
22
22
|
# @return [type] the cleaned value
|
|
23
|
-
def self.mungify(type, value, error_msg_prefix, unpack_strings = false)
|
|
23
|
+
def self.mungify(type, value, error_msg_prefix, unpack_strings = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
24
24
|
cleaned_value = mungify_core(
|
|
25
25
|
type,
|
|
26
26
|
value,
|
|
27
27
|
error_msg_prefix,
|
|
28
|
-
unpack_strings
|
|
28
|
+
unpack_strings
|
|
29
29
|
)
|
|
30
30
|
validate(type, cleaned_value, error_msg_prefix)
|
|
31
31
|
cleaned_value
|
|
@@ -42,13 +42,14 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
42
42
|
# @return [type] the cleaned value
|
|
43
43
|
# @raise [Puppet::ResourceError] if `value` could not be parsed into `type`
|
|
44
44
|
# @private
|
|
45
|
-
def self.mungify_core(type, value, error_msg_prefix, unpack_strings = false)
|
|
45
|
+
def self.mungify_core(type, value, error_msg_prefix, unpack_strings = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
46
46
|
if unpack_strings
|
|
47
47
|
# When the provider is exercised from the `puppet resource` CLI, we need
|
|
48
48
|
# to unpack strings into the correct types, e.g. "1" (a string)
|
|
49
49
|
# to 1 (an integer)
|
|
50
50
|
cleaned_value, error_msg = try_mungify(type, value, error_msg_prefix)
|
|
51
51
|
raise Puppet::ResourceError, error_msg if error_msg
|
|
52
|
+
|
|
52
53
|
cleaned_value
|
|
53
54
|
elsif value == :false # rubocop:disable Lint/BooleanSymbol
|
|
54
55
|
# work around https://tickets.puppetlabs.com/browse/PUP-2368
|
|
@@ -77,18 +78,14 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
77
78
|
end
|
|
78
79
|
# only convert the values if none failed. otherwise fall through and
|
|
79
80
|
# rely on puppet to render a proper error
|
|
80
|
-
if conversions.all? { |c| c[1].nil? }
|
|
81
|
-
value = conversions.map { |c| c[0] }
|
|
82
|
-
end
|
|
81
|
+
value = conversions.map { |c| c[0] } if conversions.all? { |c| c[1].nil? }
|
|
83
82
|
end
|
|
84
83
|
when Puppet::Pops::Types::PBooleanType
|
|
85
84
|
value = boolean_munge(value)
|
|
86
85
|
when Puppet::Pops::Types::PIntegerType,
|
|
87
86
|
Puppet::Pops::Types::PFloatType,
|
|
88
87
|
Puppet::Pops::Types::PNumericType
|
|
89
|
-
if value.is_a?(String) && (value.match?(
|
|
90
|
-
value = Puppet::Pops::Utils.to_n(value)
|
|
91
|
-
end
|
|
88
|
+
value = Puppet::Pops::Utils.to_n(value) if value.is_a?(String) && (value.match?(/^-?\d+$/) || value.match?(Puppet::Pops::Patterns::NUMERIC))
|
|
92
89
|
when Puppet::Pops::Types::PEnumType,
|
|
93
90
|
Puppet::Pops::Types::PStringType,
|
|
94
91
|
Puppet::Pops::Types::PPatternType
|
|
@@ -109,9 +106,7 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
109
106
|
return conversion_results[0] if conversion_results.length == 1
|
|
110
107
|
|
|
111
108
|
# return an error if ambiguous
|
|
112
|
-
if conversion_results.length > 1
|
|
113
|
-
return [nil, ambiguous_error_msg(error_msg_prefix, value, type)]
|
|
114
|
-
end
|
|
109
|
+
return [nil, ambiguous_error_msg(error_msg_prefix, value, type)] if conversion_results.length > 1
|
|
115
110
|
|
|
116
111
|
# try to interpret as string
|
|
117
112
|
return try_mungify(string_type, value, error_msg_prefix) if string_type
|
|
@@ -121,6 +116,7 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
121
116
|
|
|
122
117
|
error_msg = try_validate(type, value, error_msg_prefix)
|
|
123
118
|
return [nil, error_msg] if error_msg # an error
|
|
119
|
+
|
|
124
120
|
[value, nil] # match
|
|
125
121
|
end
|
|
126
122
|
|
|
@@ -146,7 +142,7 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
146
142
|
# @private
|
|
147
143
|
def self.ambiguous_error_msg(error_msg_prefix, value, type)
|
|
148
144
|
"#{error_msg_prefix} #{value.inspect} is not unabiguously convertable to " \
|
|
149
|
-
|
|
145
|
+
"#{type}"
|
|
150
146
|
end
|
|
151
147
|
|
|
152
148
|
# Validates the `value` against the specified `type`.
|
|
@@ -171,16 +167,16 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
171
167
|
|
|
172
168
|
# an error :-(
|
|
173
169
|
inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value)
|
|
174
|
-
|
|
170
|
+
Puppet::Pops::Types::TypeMismatchDescriber.new.describe_mismatch(
|
|
175
171
|
error_msg_prefix,
|
|
176
172
|
type,
|
|
177
|
-
inferred_type
|
|
173
|
+
inferred_type
|
|
178
174
|
)
|
|
179
|
-
error_msg
|
|
180
175
|
end
|
|
181
176
|
|
|
182
177
|
def self.validate_ensure(definition)
|
|
183
178
|
return unless definition[:attributes].key? :ensure
|
|
179
|
+
|
|
184
180
|
options = definition[:attributes][:ensure]
|
|
185
181
|
type = parse_puppet_type(:ensure, options[:type])
|
|
186
182
|
|
|
@@ -199,9 +195,9 @@ module Puppet::ResourceApi::DataTypeHandling
|
|
|
199
195
|
Puppet::Pops::Types::TypeParser.singleton.parse(type)
|
|
200
196
|
rescue Puppet::ParseErrorWithIssue => e
|
|
201
197
|
raise Puppet::DevError, "The type of the `#{attr_name}` attribute " \
|
|
202
|
-
|
|
198
|
+
"`#{type}` could not be parsed: #{e.message}"
|
|
203
199
|
rescue Puppet::ParseError => e
|
|
204
200
|
raise Puppet::DevError, "The type of the `#{attr_name}` attribute " \
|
|
205
|
-
|
|
201
|
+
"`#{type}` is not recognised: #{e.message}"
|
|
206
202
|
end
|
|
207
203
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'yaml'
|
|
4
4
|
|
|
5
5
|
module Puppet; end # rubocop:disable Style/Documentation
|
|
6
|
+
|
|
6
7
|
module Puppet::ResourceApi
|
|
7
8
|
# A trivial class to provide the functionality required to push data through the existing type/provider parts of puppet
|
|
8
9
|
class ResourceShim
|
|
@@ -45,7 +46,7 @@ module Puppet::ResourceApi
|
|
|
45
46
|
# Convert our resource to yaml for Hiera purposes.
|
|
46
47
|
def to_hierayaml
|
|
47
48
|
attributes = Hash[filtered_keys.map { |k| [k.to_s, values[k]] }]
|
|
48
|
-
YAML.dump('type' => { title => attributes }).split("\n").drop(2).join("\n")
|
|
49
|
+
"#{YAML.dump('type' => { title => attributes }).split("\n").drop(2).join("\n")}\n"
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
def to_json(*)
|
|
@@ -70,12 +71,8 @@ module Puppet::ResourceApi
|
|
|
70
71
|
class MonkeyHash < Hash
|
|
71
72
|
def <=>(other)
|
|
72
73
|
result = self.class.name <=> other.class.name
|
|
73
|
-
if result.zero?
|
|
74
|
-
|
|
75
|
-
end
|
|
76
|
-
if result.zero?
|
|
77
|
-
result = keys.sort.map { |k| self[k] } <=> other.keys.sort.map { |k| other[k] }
|
|
78
|
-
end
|
|
74
|
+
result = keys.sort <=> other.keys.sort if result.zero?
|
|
75
|
+
result = keys.sort.map { |k| self[k] } <=> other.keys.sort.map { |k| other[k] } if result.zero?
|
|
79
76
|
result
|
|
80
77
|
end
|
|
81
78
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'puppet/util'
|
|
4
4
|
require 'puppet/parameter'
|
|
5
5
|
|
|
6
|
-
module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation
|
|
6
|
+
module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation
|
|
7
7
|
|
|
8
8
|
# Class containing parameter functionality for ResourceApi.
|
|
9
9
|
class Puppet::ResourceApi::Parameter < Puppet::Parameter
|
|
@@ -30,7 +30,7 @@ class Puppet::ResourceApi::Parameter < Puppet::Parameter
|
|
|
30
30
|
@data_type,
|
|
31
31
|
value,
|
|
32
32
|
"#{@type_name}.#{@attribute_name}",
|
|
33
|
-
Puppet::ResourceApi.caller_is_resource_app
|
|
33
|
+
Puppet::ResourceApi.caller_is_resource_app?
|
|
34
34
|
)
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'puppet/util'
|
|
4
4
|
require 'puppet/property'
|
|
5
5
|
|
|
6
|
-
module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation
|
|
6
|
+
module Puppet; module ResourceApi; end; end # predeclare the main module # rubocop:disable Style/Documentation
|
|
7
7
|
|
|
8
8
|
# Class containing property functionality for ResourceApi.
|
|
9
9
|
class Puppet::ResourceApi::Property < Puppet::Property
|
|
@@ -27,9 +27,7 @@ class Puppet::ResourceApi::Property < Puppet::Property
|
|
|
27
27
|
# Define class method insync?(is) if the custom_insync feature flag is set
|
|
28
28
|
if referrable_type&.type_definition&.feature?('custom_insync')
|
|
29
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
|
|
30
|
+
@change_to_s_value = 'Custom insync logic determined that this resource is out of sync' if @attribute_name == :rsapi_custom_insync_trigger
|
|
33
31
|
# Define class method insync?(is) if the name is :ensure and custom_insync feature flag is not set
|
|
34
32
|
elsif @attribute_name == :ensure
|
|
35
33
|
def_ensure_insync?
|
|
@@ -62,9 +60,7 @@ class Puppet::ResourceApi::Property < Puppet::Property
|
|
|
62
60
|
def should=(value)
|
|
63
61
|
@shouldorig = value
|
|
64
62
|
|
|
65
|
-
if @attribute_name == :ensure
|
|
66
|
-
value = value.to_s
|
|
67
|
-
end
|
|
63
|
+
value = value.to_s if @attribute_name == :ensure
|
|
68
64
|
|
|
69
65
|
# Puppet requires the @should value to always be stored as an array. We do not use this
|
|
70
66
|
# for anything else
|
|
@@ -74,8 +70,8 @@ class Puppet::ResourceApi::Property < Puppet::Property
|
|
|
74
70
|
@data_type,
|
|
75
71
|
value,
|
|
76
72
|
"#{@type_name}.#{@attribute_name}",
|
|
77
|
-
Puppet::ResourceApi.caller_is_resource_app
|
|
78
|
-
)
|
|
73
|
+
Puppet::ResourceApi.caller_is_resource_app?
|
|
74
|
+
)
|
|
79
75
|
]
|
|
80
76
|
end
|
|
81
77
|
|
|
@@ -104,21 +100,20 @@ class Puppet::ResourceApi::Property < Puppet::Property
|
|
|
104
100
|
|
|
105
101
|
provider_insync_result, change_message = provider.insync?(context, title, @attribute_name, is_hash, should_hash)
|
|
106
102
|
|
|
107
|
-
unless provider_insync_result.nil? || change_message.nil? || change_message.empty?
|
|
108
|
-
@change_to_s_value = change_message
|
|
109
|
-
end
|
|
103
|
+
@change_to_s_value = change_message unless provider_insync_result.nil? || change_message.nil? || change_message.empty?
|
|
110
104
|
|
|
111
105
|
case provider_insync_result
|
|
112
106
|
when nil
|
|
113
107
|
# If validating ensure and no custom insync was used, check if rs_value matches is.
|
|
114
108
|
return rs_value.to_s == is.to_s if @attribute_name == :ensure
|
|
109
|
+
|
|
115
110
|
# Otherwise, super and rely on Puppet::Property.insync?
|
|
116
111
|
super(is)
|
|
117
112
|
when TrueClass, FalseClass
|
|
118
|
-
|
|
113
|
+
provider_insync_result
|
|
119
114
|
else
|
|
120
115
|
# 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
|
|
116
|
+
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 Layout/LineLength
|
|
122
117
|
end
|
|
123
118
|
end
|
|
124
119
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Style/Documentation
|
|
4
|
+
module Puppet; end
|
|
5
|
+
module Puppet::ResourceApi; end
|
|
6
|
+
# rubocop:enable Style/Documentation
|
|
7
|
+
|
|
8
|
+
# This class provides a simple caching mechanism to support minimizing get()
|
|
9
|
+
# calls into a provider.
|
|
10
|
+
class Puppet::ResourceApi::ProviderGetCache
|
|
11
|
+
def initialize
|
|
12
|
+
clear
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def clear
|
|
16
|
+
@cache = {}
|
|
17
|
+
@cached_all = false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def all
|
|
21
|
+
raise 'all method called, but cached_all not called' unless @cached_all
|
|
22
|
+
|
|
23
|
+
@cache.values
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def add(key, value)
|
|
27
|
+
@cache[key] = value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get(key)
|
|
31
|
+
@cache[key]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def cached_all
|
|
35
|
+
@cached_all = true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def cached_all?
|
|
39
|
+
@cached_all
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -9,6 +9,7 @@ class Puppet::ResourceApi::PuppetContext < Puppet::ResourceApi::BaseContext
|
|
|
9
9
|
def device
|
|
10
10
|
# TODO: evaluate facter_url setting for loading config if there is no `current` NetworkDevice
|
|
11
11
|
raise 'no device configured' unless Puppet::Util::NetworkDevice.current
|
|
12
|
+
|
|
12
13
|
Puppet::Util::NetworkDevice.current
|
|
13
14
|
end
|
|
14
15
|
|
|
@@ -6,15 +6,17 @@ module Puppet::ResourceApi
|
|
|
6
6
|
# This class provides a default implementation for set(), when your resource does not benefit from batching.
|
|
7
7
|
# Instead of processing changes yourself, the `create`, `update`, and `delete` functions, are called for you,
|
|
8
8
|
# with proper logging already set up.
|
|
9
|
-
# Note that your type needs to use `
|
|
10
|
-
# and absence of resources.
|
|
9
|
+
# Note that your type needs to use `ensure` in the conventional way with values of `prsesent`
|
|
10
|
+
# and `absent` to signal presence and absence of resources.
|
|
11
11
|
class SimpleProvider
|
|
12
12
|
def set(context, changes)
|
|
13
|
+
namevars = context.type.namevars
|
|
14
|
+
|
|
13
15
|
changes.each do |name, change|
|
|
14
16
|
is = if context.type.feature?('simple_get_filter')
|
|
15
|
-
change.key?(:is) ? change[:is] : (get(context, [name]) || []).find { |r| r
|
|
17
|
+
change.key?(:is) ? change[:is] : (get(context, [name]) || []).find { |r| SimpleProvider.build_name(namevars, r) == name }
|
|
16
18
|
else
|
|
17
|
-
change.key?(:is) ? change[:is] : (get(context) || []).find { |r| r
|
|
19
|
+
change.key?(:is) ? change[:is] : (get(context) || []).find { |r| SimpleProvider.build_name(namevars, r) == name }
|
|
18
20
|
end
|
|
19
21
|
context.type.check_schema(is) unless change.key?(:is)
|
|
20
22
|
|
|
@@ -22,13 +24,13 @@ module Puppet::ResourceApi
|
|
|
22
24
|
|
|
23
25
|
raise 'SimpleProvider cannot be used with a Type that is not ensurable' unless context.type.ensurable?
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
is_ensure = is.nil? ? 'absent' : is[:ensure].to_s
|
|
28
|
+
should_ensure = should.nil? ? 'absent' : should[:ensure].to_s
|
|
27
29
|
|
|
28
|
-
name_hash = if
|
|
30
|
+
name_hash = if namevars.length > 1
|
|
29
31
|
# pass a name_hash containing the values of all namevars
|
|
30
32
|
name_hash = {}
|
|
31
|
-
|
|
33
|
+
namevars.each do |namevar|
|
|
32
34
|
name_hash[namevar] = change[:should][namevar]
|
|
33
35
|
end
|
|
34
36
|
name_hash
|
|
@@ -36,15 +38,15 @@ module Puppet::ResourceApi
|
|
|
36
38
|
name
|
|
37
39
|
end
|
|
38
40
|
|
|
39
|
-
if
|
|
41
|
+
if is_ensure == 'absent' && should_ensure == 'present'
|
|
40
42
|
context.creating(name) do
|
|
41
43
|
create(context, name_hash, should)
|
|
42
44
|
end
|
|
43
|
-
elsif
|
|
45
|
+
elsif is_ensure == 'present' && should_ensure == 'absent'
|
|
44
46
|
context.deleting(name) do
|
|
45
47
|
delete(context, name_hash)
|
|
46
48
|
end
|
|
47
|
-
elsif
|
|
49
|
+
elsif is_ensure == 'present'
|
|
48
50
|
context.updating(name) do
|
|
49
51
|
update(context, name_hash, should)
|
|
50
52
|
end
|
|
@@ -65,14 +67,12 @@ module Puppet::ResourceApi
|
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
# @api private
|
|
68
|
-
def self.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
result[:ensure] = 'absent'
|
|
75
|
-
result
|
|
70
|
+
def self.build_name(namevars, resource_hash)
|
|
71
|
+
if namevars.size > 1
|
|
72
|
+
Hash[namevars.map { |attr| [attr, resource_hash[attr]] }]
|
|
73
|
+
else
|
|
74
|
+
resource_hash[namevars[0]]
|
|
75
|
+
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
end
|
|
@@ -13,6 +13,7 @@ class Puppet::ResourceApi::Transport::Wrapper
|
|
|
13
13
|
url = URI.parse(url_or_config_or_transport)
|
|
14
14
|
raise "Unexpected url '#{url_or_config_or_transport}' found. Only file:/// URLs for configuration supported at the moment." unless url.scheme == 'file'
|
|
15
15
|
raise "Trying to load config from '#{url.path}, but file does not exist." if url && !File.exist?(url.path)
|
|
16
|
+
|
|
16
17
|
config = self.class.deep_symbolize(Hocon.load(url.path, syntax: Hocon::ConfigSyntax::HOCON) || {})
|
|
17
18
|
elsif url_or_config_or_transport.is_a? Hash
|
|
18
19
|
config = url_or_config_or_transport
|
|
@@ -25,7 +26,7 @@ class Puppet::ResourceApi::Transport::Wrapper
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def transport_class?(name, transport)
|
|
28
|
-
class_name = name.split('_').map
|
|
29
|
+
class_name = name.split('_').map(&:capitalize).join
|
|
29
30
|
expected = Puppet::Transport.const_get(class_name).to_s
|
|
30
31
|
expected == transport.class.to_s
|
|
31
32
|
end
|
|
@@ -40,9 +41,9 @@ class Puppet::ResourceApi::Transport::Wrapper
|
|
|
40
41
|
(@transport.respond_to? name) || super
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
def method_missing(method_name,
|
|
44
|
+
def method_missing(method_name, ...)
|
|
44
45
|
if @transport.respond_to? method_name
|
|
45
|
-
@transport.send(method_name,
|
|
46
|
+
@transport.send(method_name, ...)
|
|
46
47
|
else
|
|
47
48
|
super
|
|
48
49
|
end
|
|
@@ -52,6 +53,7 @@ class Puppet::ResourceApi::Transport::Wrapper
|
|
|
52
53
|
def self.deep_symbolize(obj)
|
|
53
54
|
return obj.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = deep_symbolize(v); } if obj.is_a? Hash
|
|
54
55
|
return obj.each_with_object([]) { |v, memo| memo << deep_symbolize(v); } if obj.is_a? Array
|
|
56
|
+
|
|
55
57
|
obj
|
|
56
58
|
end
|
|
57
59
|
end
|
|
@@ -5,26 +5,26 @@ module Puppet::ResourceApi; end # rubocop:disable Style/Documentation
|
|
|
5
5
|
# Remote target transport API
|
|
6
6
|
module Puppet::ResourceApi::Transport
|
|
7
7
|
def register(schema)
|
|
8
|
-
raise Puppet::DevError, 'requires a hash as schema, not
|
|
8
|
+
raise Puppet::DevError, format('requires a hash as schema, not `%<other_type>s`', other_type: schema.class) unless schema.is_a? Hash
|
|
9
9
|
raise Puppet::DevError, 'requires a `:name`' unless schema.key? :name
|
|
10
10
|
raise Puppet::DevError, 'requires `:desc`' unless schema.key? :desc
|
|
11
11
|
raise Puppet::DevError, 'requires `:connection_info`' unless schema.key? :connection_info
|
|
12
|
-
raise Puppet::DevError, '`:connection_info` must be a hash, not
|
|
12
|
+
raise Puppet::DevError, format('`:connection_info` must be a hash, not `%<other_type>s`', other_type: schema[:connection_info].class) unless schema[:connection_info].is_a?(Hash)
|
|
13
|
+
|
|
13
14
|
if schema[:connection_info_order].nil?
|
|
14
15
|
schema[:connection_info_order] = schema[:connection_info].keys
|
|
15
16
|
else
|
|
16
|
-
|
|
17
|
+
unless schema[:connection_info_order].is_a?(Array)
|
|
18
|
+
raise Puppet::DevError,
|
|
19
|
+
format('`:connection_info_order` must be an array, not `%<other_type>s`', other_type: schema[:connection_info_order].class)
|
|
20
|
+
end
|
|
17
21
|
end
|
|
18
22
|
|
|
19
|
-
unless transports[schema[:name]].nil?
|
|
20
|
-
|
|
21
|
-
name: schema[:name],
|
|
22
|
-
environment: current_environment_name,
|
|
23
|
-
}
|
|
24
|
-
end
|
|
23
|
+
raise Puppet::DevError, format('Transport `%<name>s` is already registered for `%<environment>s`', name: schema[:name], environment: current_environment_name) unless transports[schema[:name]].nil?
|
|
24
|
+
|
|
25
25
|
transports[schema[:name]] = Puppet::ResourceApi::TransportSchemaDef.new(schema)
|
|
26
26
|
end
|
|
27
|
-
module_function :register
|
|
27
|
+
module_function :register
|
|
28
28
|
|
|
29
29
|
# retrieve a Hash of transport schemas, keyed by their name.
|
|
30
30
|
# Only already loaded transports are returned.
|
|
@@ -33,7 +33,7 @@ module Puppet::ResourceApi::Transport
|
|
|
33
33
|
def list
|
|
34
34
|
Marshal.load(Marshal.dump(transports))
|
|
35
35
|
end
|
|
36
|
-
module_function :list
|
|
36
|
+
module_function :list
|
|
37
37
|
|
|
38
38
|
# retrieve a Hash of transport schemas, keyed by their name.
|
|
39
39
|
# This uses the Puppet autoloader, provide an environment name as `force_environment`
|
|
@@ -46,7 +46,7 @@ module Puppet::ResourceApi::Transport
|
|
|
46
46
|
Marshal.load(Marshal.dump(transports))
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
|
-
module_function :list_all_transports
|
|
49
|
+
module_function :list_all_transports
|
|
50
50
|
|
|
51
51
|
# Loads all schemas using the Puppet Autoloader. This method is clearing the cache and forcing `Kernel.load`, so that the cache is up-to-date.
|
|
52
52
|
def self.load_all_schemas
|
|
@@ -73,10 +73,10 @@ module Puppet::ResourceApi::Transport
|
|
|
73
73
|
def connect(name, connection_info)
|
|
74
74
|
validate(name, connection_info)
|
|
75
75
|
require "puppet/transport/#{name}"
|
|
76
|
-
class_name = name.split('_').map
|
|
76
|
+
class_name = name.split('_').map(&:capitalize).join
|
|
77
77
|
Puppet::Transport.const_get(class_name).new(get_context(name), wrap_sensitive(name, connection_info))
|
|
78
78
|
end
|
|
79
|
-
module_function :connect
|
|
79
|
+
module_function :connect
|
|
80
80
|
|
|
81
81
|
def inject_device(name, transport)
|
|
82
82
|
transport_wrapper = Puppet::ResourceApi::Transport::Wrapper.new(name, transport)
|
|
@@ -87,21 +87,14 @@ module Puppet::ResourceApi::Transport
|
|
|
87
87
|
Puppet::Util::NetworkDevice.instance_variable_set(:@current, transport_wrapper)
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
-
module_function :inject_device
|
|
90
|
+
module_function :inject_device
|
|
91
91
|
|
|
92
92
|
def self.validate(name, connection_info)
|
|
93
93
|
require "puppet/transport/schema/#{name}" unless transports.key? name
|
|
94
94
|
transport_schema = transports[name]
|
|
95
|
-
if transport_schema.nil?
|
|
96
|
-
raise Puppet::DevError, 'Transport for `%{target}` not registered with `%{environment}`' % {
|
|
97
|
-
target: name,
|
|
98
|
-
environment: current_environment_name,
|
|
99
|
-
}
|
|
100
|
-
end
|
|
95
|
+
raise Puppet::DevError, format('Transport for `%<target>s` not registered with `%<environment>s`', target: name, environment: current_environment_name) if transport_schema.nil?
|
|
101
96
|
|
|
102
|
-
if connection_info.key?(:
|
|
103
|
-
clean_bolt_attributes(transport_schema, connection_info)
|
|
104
|
-
end
|
|
97
|
+
clean_bolt_attributes(transport_schema, connection_info) if connection_info.key?(:'remote-transport')
|
|
105
98
|
|
|
106
99
|
apply_defaults(transport_schema, connection_info)
|
|
107
100
|
message_prefix = 'The connection info provided does not match the Transport Schema'
|
|
@@ -133,7 +126,7 @@ module Puppet::ResourceApi::Transport
|
|
|
133
126
|
context = get_context(transport_schema.name)
|
|
134
127
|
transport_schema.attributes.each do |attr_name, options|
|
|
135
128
|
if options.key?(:default) && connection_info.key?(attr_name) == false
|
|
136
|
-
context.debug('Using default value for attribute:
|
|
129
|
+
context.debug(format('Using default value for attribute: %<attribute_name>s, value: %<default_value>s', attribute_name: attr_name, default_value: options[:default].inspect))
|
|
137
130
|
connection_info[attr_name] = options[:default]
|
|
138
131
|
end
|
|
139
132
|
end
|
|
@@ -161,25 +154,25 @@ module Puppet::ResourceApi::Transport
|
|
|
161
154
|
context = get_context(transport_schema.name)
|
|
162
155
|
|
|
163
156
|
# Attributes we expect from bolt, but want to ignore if the transport does not expect them
|
|
164
|
-
[
|
|
157
|
+
%i[uri host protocol user port password].each do |attribute_name|
|
|
165
158
|
if connection_info.key?(attribute_name) && !transport_schema.attributes.key?(attribute_name)
|
|
166
|
-
context.info('Discarding superfluous bolt attribute:
|
|
159
|
+
context.info(format('Discarding superfluous bolt attribute: %<attribute_name>s', attribute_name: attribute_name))
|
|
167
160
|
connection_info.delete(attribute_name)
|
|
168
161
|
end
|
|
169
162
|
end
|
|
170
163
|
|
|
171
164
|
# Attributes that bolt emits, but we want to ignore if the transport does not expect them
|
|
172
|
-
([
|
|
165
|
+
(%i[name path query run-on remote-transport implementations] + connection_info.keys.select { |k| k.to_s.start_with? 'remote-' }).each do |attribute_name|
|
|
173
166
|
if connection_info.key?(attribute_name) && !transport_schema.attributes.key?(attribute_name)
|
|
174
|
-
context.debug('Discarding bolt metaparameter:
|
|
167
|
+
context.debug(format('Discarding bolt metaparameter: %<attribute_name>s', attribute_name: attribute_name))
|
|
175
168
|
connection_info.delete(attribute_name)
|
|
176
169
|
end
|
|
177
170
|
end
|
|
178
171
|
|
|
179
172
|
# remove any other attributes the transport is not prepared to handle
|
|
180
|
-
connection_info.
|
|
173
|
+
connection_info.each_key do |attribute_name|
|
|
181
174
|
if connection_info.key?(attribute_name) && !transport_schema.attributes.key?(attribute_name)
|
|
182
|
-
context.warning('Discarding unknown attribute:
|
|
175
|
+
context.warning(format('Discarding unknown attribute: %<attribute_name>s', attribute_name: attribute_name))
|
|
183
176
|
connection_info.delete(attribute_name)
|
|
184
177
|
end
|
|
185
178
|
end
|