bolt 1.49.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bolt might be problematic. Click here for more details.

Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +6 -6
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +24 -45
  4. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +3 -3
  5. data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +1 -1
  6. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +10 -12
  7. data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -1
  8. data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +3 -3
  9. data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +5 -4
  10. data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +1 -3
  11. data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +1 -2
  12. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +2 -2
  13. data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +2 -2
  14. data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +1 -1
  15. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +7 -3
  16. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +15 -31
  17. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +9 -5
  18. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +9 -3
  19. data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +4 -3
  20. data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +6 -6
  21. data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +2 -2
  22. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +7 -3
  23. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +6 -2
  24. data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +2 -2
  25. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +2 -1
  26. data/bolt-modules/file/lib/puppet/functions/file/exists.rb +2 -1
  27. data/bolt-modules/file/lib/puppet/functions/file/join.rb +1 -0
  28. data/bolt-modules/file/lib/puppet/functions/file/read.rb +1 -0
  29. data/bolt-modules/file/lib/puppet/functions/file/readable.rb +2 -1
  30. data/bolt-modules/out/lib/puppet/functions/out/message.rb +1 -1
  31. data/bolt-modules/system/lib/puppet/functions/system/env.rb +1 -0
  32. data/lib/bolt/applicator.rb +70 -118
  33. data/lib/bolt/apply_target.rb +1 -1
  34. data/lib/bolt/bolt_option_parser.rb +21 -37
  35. data/lib/bolt/catalog.rb +5 -22
  36. data/lib/bolt/catalog/logging.rb +1 -1
  37. data/lib/bolt/cli.rb +33 -44
  38. data/lib/bolt/config.rb +15 -18
  39. data/lib/bolt/error.rb +2 -2
  40. data/lib/bolt/executor.rb +32 -40
  41. data/lib/bolt/inventory.rb +9 -367
  42. data/lib/bolt/inventory/group.rb +293 -182
  43. data/lib/bolt/inventory/{inventory2.rb → inventory.rb} +25 -14
  44. data/lib/bolt/inventory/target.rb +1 -1
  45. data/lib/bolt/module.rb +4 -4
  46. data/lib/bolt/outputter/human.rb +11 -6
  47. data/lib/bolt/outputter/json.rb +3 -11
  48. data/lib/bolt/pal.rb +1 -2
  49. data/lib/bolt/pal/yaml_plan/step/resources.rb +1 -1
  50. data/lib/bolt/plugin.rb +1 -1
  51. data/lib/bolt/plugin/module.rb +19 -36
  52. data/lib/bolt/plugin/prompt.rb +2 -4
  53. data/lib/bolt/puppetdb/config.rb +1 -3
  54. data/lib/bolt/result.rb +3 -6
  55. data/lib/bolt/secret/base.rb +0 -6
  56. data/lib/bolt/target.rb +8 -219
  57. data/lib/bolt/transport/local/shell.rb +9 -13
  58. data/lib/bolt/transport/orch.rb +3 -5
  59. data/lib/bolt/transport/ssh.rb +1 -0
  60. data/lib/bolt/transport/ssh/connection.rb +1 -4
  61. data/lib/bolt/transport/winrm/connection.rb +1 -1
  62. data/lib/bolt/util.rb +2 -8
  63. data/lib/bolt/version.rb +1 -1
  64. data/lib/bolt_server/transport_app.rb +35 -17
  65. data/lib/bolt_spec/plans.rb +8 -2
  66. data/libexec/bolt_catalog +19 -5
  67. metadata +4 -8
  68. data/exe/bolt-inventory-pdb +0 -13
  69. data/lib/bolt/inventory/group2.rb +0 -403
  70. data/lib/bolt_ext/puppetdb_inventory.rb +0 -129
@@ -1,25 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bolt/inventory/group2'
3
+ require 'bolt/inventory/group'
4
4
  require 'bolt/inventory/target'
5
5
 
6
6
  module Bolt
7
7
  class Inventory
8
- class Inventory2
8
+ class Inventory
9
9
  attr_reader :targets, :plugins, :config
10
- # This uses "targets" in the message instead of "nodes"
11
10
  class WildcardError < Bolt::Error
12
11
  def initialize(target)
13
12
  super("Found 0 targets matching wildcard pattern #{target}", 'bolt.inventory/wildcard-error')
14
13
  end
15
14
  end
16
15
 
17
- def initialize(data, config = nil, plugins: nil)
16
+ def initialize(data, config = nil, plugins:)
18
17
  @logger = Logging.logger[self]
19
18
  # Config is saved to add config options to targets
20
19
  @config = config || Bolt::Config.default
21
20
  @data = data || {}
22
- @groups = Group2.new(@data.merge('name' => 'all'), plugins)
21
+ @groups = Group.new(@data.merge('name' => 'all'), plugins)
23
22
  @plugins = plugins
24
23
  @group_lookup = {}
25
24
  # The targets hash is the canonical source for all targets in inventory
@@ -37,7 +36,7 @@ module Bolt
37
36
  end
38
37
 
39
38
  def target_implementation_class
40
- Bolt::Target2
39
+ Bolt::Target
41
40
  end
42
41
 
43
42
  def collect_groups
@@ -84,6 +83,20 @@ module Bolt
84
83
  }
85
84
  end
86
85
 
86
+ def self.localhost_defaults(data)
87
+ defaults = {
88
+ 'config' => {
89
+ 'transport' => 'local',
90
+ 'local' => { 'interpreters' => { '.rb' => RbConfig.ruby } }
91
+ },
92
+ 'features' => ['puppet-agent']
93
+ }
94
+ data = Bolt::Util.deep_merge(defaults, data)
95
+ # If features is an empty array deep_merge won't add the puppet-agent
96
+ data['features'] += ['puppet-agent'] if data['features'].empty?
97
+ data
98
+ end
99
+
87
100
  #### PRIVATE ####
88
101
  def group_data_for(target_name)
89
102
  @groups.group_collect(target_name)
@@ -115,7 +128,7 @@ module Bolt
115
128
  private :resolve_name
116
129
 
117
130
  def expand_targets(targets)
118
- if targets.is_a? Bolt::Target2
131
+ if targets.is_a? Bolt::Target
119
132
  targets
120
133
  elsif targets.is_a? Array
121
134
  targets.map { |tish| expand_targets(tish) }
@@ -125,11 +138,11 @@ module Bolt
125
138
  ts = resolve_name(name)
126
139
  ts.map do |t|
127
140
  # If the target doesn't exist, evaluate it from the inventory.
128
- # Then return a Bolt::Target2.
141
+ # Then return a Bolt::Target.
129
142
  unless @targets.key?(t)
130
143
  @targets[t] = create_target_from_inventory(t)
131
144
  end
132
- Bolt::Target2.new(t, self)
145
+ Bolt::Target.new(t, self)
133
146
  end
134
147
  end
135
148
  end
@@ -182,8 +195,8 @@ module Bolt
182
195
 
183
196
  # Add a brand new target, overriding any existing target with the same
184
197
  # name. This method does not honor target config from the inventory. This
185
- # is used when Target.new is called from a plan.
186
- def create_target_from_plan(data)
198
+ # is used when Target.new is called from a plan or with a data hash.
199
+ def create_target_from_hash(data)
187
200
  # If target already exists, delete old and replace with new, otherwise add to new to all group
188
201
  new_target = Bolt::Inventory::Target.new(data, self)
189
202
  existing_target = @targets.key?(new_target.name)
@@ -257,9 +270,7 @@ module Bolt
257
270
 
258
271
  def add_facts(target, new_facts = {})
259
272
  @targets[target.name].add_facts(new_facts)
260
- # rubocop:disable Style/GlobalVars
261
- $future ? target : facts(target)
262
- # rubocop:enable Style/GlobalVars
273
+ target
263
274
  end
264
275
 
265
276
  def facts(target)
@@ -207,7 +207,7 @@ module Bolt
207
207
 
208
208
  # This should be handled by `get_targets`
209
209
  if @name == 'localhost'
210
- group_data = Bolt::Inventory.localhost_defaults(group_data)
210
+ group_data = Bolt::Inventory::Inventory.localhost_defaults(group_data)
211
211
  end
212
212
 
213
213
  @group_cache = group_data
@@ -8,10 +8,10 @@ module Bolt
8
8
  def self.discover(modulepath)
9
9
  modulepath.each_with_object({}) do |path, mods|
10
10
  next unless File.exist?(path) && File.directory?(path)
11
- (Dir.entries(path) - %w[. ..])
12
- .map { |dir| File.join(path, dir) }
13
- .select { |dir| File.directory?(dir) }
14
- .each do |dir|
11
+ Dir.children(path)
12
+ .map { |dir| File.join(path, dir) }
13
+ .select { |dir| File.directory?(dir) }
14
+ .each do |dir|
15
15
  module_name = File.basename(dir)
16
16
  if module_name =~ MODULE_NAME_REGEX
17
17
  # Puppet will load some objects from shadowed modules but this won't
@@ -346,18 +346,23 @@ module Bolt
346
346
  # @param [Bolt::PlanResult] plan_result A PlanResult object
347
347
  def print_plan_result(plan_result)
348
348
  value = plan_result.value
349
- if value.nil?
349
+ case value
350
+ when nil
350
351
  @stream.puts("Plan completed successfully with no result")
351
- elsif value.is_a? Bolt::ApplyFailure
352
- @stream.puts(colorize(:red, value.message))
353
- elsif value.is_a? Bolt::ResultSet
354
- value.each { |result| print_result(result) }
355
- print_summary(value)
352
+ when Bolt::ApplyFailure, Bolt::RunFailure
353
+ print_result_set(value.result_set)
354
+ when Bolt::ResultSet
355
+ print_result_set(value)
356
356
  else
357
357
  @stream.puts(::JSON.pretty_generate(plan_result, quirks_mode: true))
358
358
  end
359
359
  end
360
360
 
361
+ def print_result_set(result_set)
362
+ result_set.each { |result| print_result(result) }
363
+ print_summary(result_set)
364
+ end
365
+
361
366
  def print_puppetfile_result(success, puppetfile, moduledir)
362
367
  if success
363
368
  @stream.puts("Successfully synced modules from #{puppetfile} to #{moduledir}")
@@ -36,17 +36,9 @@ module Bolt
36
36
  @stream.puts "],\n"
37
37
  @preceding_item = false
38
38
  @items_open = false
39
- # rubocop:disable Style/GlobalVars
40
- if $future
41
- @stream.puts format('"target_count": %<size>d, "elapsed_time": %<elapsed>d }',
42
- size: results.size,
43
- elapsed: elapsed_time)
44
- else
45
- @stream.puts format('"node_count": %<size>d, "elapsed_time": %<elapsed>d }',
46
- size: results.size,
47
- elapsed: elapsed_time)
48
- end
49
- # rubocop:enable Style/GlobalVars
39
+ @stream.puts format('"target_count": %<size>d, "elapsed_time": %<elapsed>d }',
40
+ size: results.size,
41
+ elapsed: elapsed_time)
50
42
  end
51
43
 
52
44
  def print_table(results)
@@ -120,8 +120,7 @@ module Bolt
120
120
  static_loader = loaders.static_loader
121
121
  static_loader.runtime_3_init
122
122
  if File.directory?(@resource_types)
123
- # Ruby 2.3 does not support Dir.children
124
- (Dir.entries(@resource_types) - %w[. ..]).each do |resource_pp|
123
+ Dir.children(@resource_types).each do |resource_pp|
125
124
  type_name_from_file = File.basename(resource_pp, '.pp').capitalize
126
125
  typed_name = Puppet::Pops::Loader::TypedName.new(:type, type_name_from_file)
127
126
  resource_type = Puppet::Pops::Types::TypeFactory.resource(type_name_from_file)
@@ -80,7 +80,7 @@ module Bolt
80
80
  declarations = @normalized_resources.map do |resource|
81
81
  type = resource['type'].is_a?(EvaluableString) ? resource['type'].value : resource['type']
82
82
  title = Bolt::Util.to_code(resource['title'])
83
- parameters = Bolt::Util.map_vals(resource['parameters']) do |val|
83
+ parameters = resource['parameters'].transform_values do |val|
84
84
  Bolt::Util.to_code(val)
85
85
  end
86
86
 
@@ -51,7 +51,7 @@ module Bolt
51
51
  private :serial_executor
52
52
 
53
53
  def empty_inventory
54
- @empty_inventory ||= Bolt::Inventory::Inventory2.new({}, plugins: @plugins)
54
+ @empty_inventory ||= Bolt::Inventory.empty
55
55
  end
56
56
  private :empty_inventory
57
57
 
@@ -6,7 +6,7 @@ module Bolt
6
6
  class Plugin
7
7
  class Module
8
8
  class InvalidPluginData < Bolt::Plugin::PluginError
9
- def initialize(plugin, msg)
9
+ def initialize(msg, plugin)
10
10
  msg = "Invalid Plugin Data for #{plugin}: #{msg}"
11
11
  super(msg, 'bolt/invalid-plugin-data')
12
12
  end
@@ -36,17 +36,17 @@ module Bolt
36
36
  def setup
37
37
  @data = load_data
38
38
  @hook_map = find_hooks(@data['hooks'] || {})
39
- # If there is a config section in bolt_plugin.json, validate against that and send
40
- # validated values nested under `_config` key. Otherwise validate againsts the intersection
41
- # of all task schemas.
42
- # TODO: remove @send_config when deprecated
43
- schema = if @data['config']
44
- @send_config = true
45
- @data['config']
46
- else
47
- extract_task_parameter_schema
48
- end
49
- @config_schema = process_schema(schema)
39
+
40
+ if @data['config']
41
+ msg = <<~MSG.chomp
42
+ Found unsupported key 'config' in bolt_plugin.json. Config for a plugin is inferred
43
+ from task parameters, with config values passed as parameters.
44
+ MSG
45
+ raise InvalidPluginData.new(msg, name)
46
+ end
47
+
48
+ # Validate againsts the intersection of all task schemas.
49
+ @config_schema = process_schema(extract_task_parameter_schema)
50
50
 
51
51
  validate_config(@config, @config_schema)
52
52
  end
@@ -59,10 +59,6 @@ module Bolt
59
59
  (@hook_map.keys + [:validate_resolve_reference]).uniq
60
60
  end
61
61
 
62
- def config?
63
- @data.include?('config') && !@data['config'].empty?
64
- end
65
-
66
62
  def load_data
67
63
  JSON.parse(File.read(@module.plugin_data_file))
68
64
  rescue JSON::ParserError => e
@@ -159,18 +155,10 @@ module Bolt
159
155
  # handled previously. That may not always be the case so filter them
160
156
  # out now.
161
157
  meta, params = opts.partition { |key, _val| key.start_with?('_') }.map(&:to_h)
158
+ params = config.merge(params)
159
+ validate_params(task, params)
162
160
 
163
- # Send config with `_config` when config is defined in bolt_plugin.json
164
- # Otherwise, merge config with params
165
- # TODO: remove @send_config when deprecated
166
- if @send_config
167
- validate_params(task, params)
168
- params['_config'] = config if config?
169
- else
170
- params = @config ? config.merge(params) : params
171
- validate_params(task, params)
172
- end
173
- params['_boltdir'] = @context.boltdir.to_s
161
+ meta['_boltdir'] = @context.boltdir.to_s
174
162
 
175
163
  [params, meta]
176
164
  end
@@ -232,15 +220,10 @@ module Bolt
232
220
  end
233
221
 
234
222
  def validate_resolve_reference(opts)
235
- # Send config with `_config` when config is defined in bolt_plugin.json
236
- # Otherwise, merge config with params
237
- # TODO: remove @send_config when deprecated
238
- if @send_config
239
- params = opts.reject { |k, _v| k.start_with?('_') }
240
- else
241
- merged = @config.merge(opts)
242
- params = merged.reject { |k, _v| k.start_with?('_') }
243
- end
223
+ # Merge config with params
224
+ merged = @config.merge(opts)
225
+ params = merged.reject { |k, _v| k.start_with?('_') }
226
+
244
227
  sig = @hook_map[:resolve_reference]['task']
245
228
  if sig
246
229
  validate_params(sig, params)
@@ -18,11 +18,9 @@ module Bolt
18
18
  end
19
19
 
20
20
  def resolve_reference(opts)
21
- # rubocop:disable Style/GlobalVars
22
- $future ? STDERR.print("#{opts['message']}: ") : STDOUT.print("#{opts['message']}: ")
21
+ STDERR.print("#{opts['message']}: ")
23
22
  value = STDIN.noecho(&:gets).chomp
24
- $future ? STDERR.puts : STDOUT.puts
25
- # rubocop:enable Style/GlobalVars
23
+ STDERR.puts
26
24
 
27
25
  value
28
26
  end
@@ -71,13 +71,11 @@ module Bolt
71
71
  def expand_paths
72
72
  %w[cacert cert key token].each do |file|
73
73
  next unless @settings[file]
74
- # rubocop:disable Style/GlobalVars
75
- @settings[file] = if $future && @boltdir_path
74
+ @settings[file] = if @boltdir_path
76
75
  File.expand_path(@settings[file], @boltdir_path)
77
76
  else
78
77
  File.expand_path(@settings[file])
79
78
  end
80
- # rubocop:enable Style/GlobalVars
81
79
  end
82
80
  end
83
81
 
@@ -111,16 +111,13 @@ module Bolt
111
111
  end
112
112
 
113
113
  def status_hash
114
- # DEPRECATION: node in status hashes is deprecated and should be removed in 2.0
115
- base = {
114
+ {
116
115
  target: @target.name,
117
116
  action: action,
118
117
  object: object,
119
- status: status
118
+ status: status,
119
+ value: @value
120
120
  }
121
- # rubocop:disable Style/GlobalVars
122
- $future ? base.merge(value: @value) : base.merge(result: @value, node: @target.name)
123
- # rubocop:enable Style/GlobalVars
124
121
  end
125
122
 
126
123
  def generic_value
@@ -34,12 +34,6 @@ module Bolt
34
34
  alias resolve_reference secret_decrypt
35
35
 
36
36
  def validate_resolve_reference(opts)
37
- # TODO: Remove deprecation warning
38
- if opts.include?('encrypted-value')
39
- msg = "Parsing error: The 'encrypted-value' key is deprecated and can no longer be used. " \
40
- "In your Bolt config files, please use 'encrypted_value' instead."
41
- raise Bolt::ValidationError, msg
42
- end
43
37
  decode(opts['encrypted_value'])
44
38
  end
45
39
  end
@@ -4,14 +4,19 @@ require 'bolt/error'
4
4
  require 'bolt/util'
5
5
 
6
6
  module Bolt
7
- class Target2
7
+ class Target
8
8
  attr_accessor :inventory
9
9
 
10
+ # Target.new from a data hash
11
+ def self.from_hash(hash, inventory)
12
+ target = inventory.create_target_from_hash(hash)
13
+ new(target.name, inventory)
14
+ end
15
+
10
16
  # Target.new from a plan initialized with a hash
11
17
  def self.from_asserted_hash(hash)
12
18
  inventory = Puppet.lookup(:bolt_inventory)
13
- target = inventory.create_target_from_plan(hash)
14
- new(target.name, inventory)
19
+ from_hash(hash, inventory)
15
20
  end
16
21
 
17
22
  # TODO: Disallow any positional argument other than URI.
@@ -146,220 +151,4 @@ module Bolt
146
151
  end
147
152
  alias == eql?
148
153
  end
149
-
150
- class Target
151
- attr_reader :options
152
- # CODEREVIEW: this feels wrong. The altertative is threading inventory through the
153
- # executor to the RemoteTransport
154
- attr_accessor :uri, :inventory
155
-
156
- PRINT_OPTS ||= %w[host user port protocol].freeze
157
-
158
- # Satisfies the Puppet datatypes API
159
- def self.from_asserted_hash(hash)
160
- if hash['uri'] && hash['options']
161
- logger = Logging.logger[self]
162
- msg = <<~MSG
163
- #{Puppet::Pops::PuppetStack.top_of_stack.join(':')}
164
- Deprecation Warning: Starting with Bolt 2.0, using 'Target.new' with an 'options' hash key will no
165
- will no longer be supported. Use 'Target.new(<config>)', where 'config' is a hash with the same
166
- structure used to define targets in the inventory V2 file. For more information see
167
- https://puppet.com/docs/bolt/latest/writing_plans.html#creating-target-objects
168
- MSG
169
- logger.warn(msg)
170
- end
171
-
172
- new(hash['uri'], hash['options'])
173
- end
174
-
175
- def self.from_asserted_args(uri, options = nil)
176
- if options
177
- logger = Logging.logger[self]
178
- msg = <<~MSG
179
- #{Puppet::Pops::PuppetStack.top_of_stack.join(':')}
180
- Deprecation Warning: Starting with Bolt 2.0, 'Target.new(<uri>, <options>)' will no
181
- longer be supported. Use 'Target.new(<config>)', where 'config' is a hash with the same
182
- structure used to define targets in the inventory V2 file. For more information see
183
- https://puppet.com/docs/bolt/latest/writing_plans.html#creating-target-objects
184
- MSG
185
- logger.warn(msg)
186
- end
187
-
188
- new(uri, options)
189
- end
190
-
191
- # URI can be passes as nil
192
- def initialize(uri, options = nil)
193
- # lazy-load expensive gem code
194
- require 'addressable/uri'
195
-
196
- @uri = uri
197
- @uri_obj = parse(uri)
198
- @options = options || {}
199
- @options.freeze
200
-
201
- if @options['user']
202
- @user = @options['user']
203
- end
204
-
205
- if @options['password']
206
- @password = @options['password']
207
- end
208
-
209
- if @options['port']
210
- @port = @options['port']
211
- end
212
-
213
- if @options['protocol']
214
- @protocol = @options['protocol']
215
- end
216
-
217
- if @options['host']
218
- @host = @options['host']
219
- end
220
-
221
- # WARNING: name should never be updated
222
- @name = @options['name'] || @uri
223
- end
224
-
225
- def update_conf(conf)
226
- @protocol = conf[:transport]
227
-
228
- t_conf = conf[:transports][transport.to_sym] || {}
229
- # Override url methods
230
- @user = t_conf['user']
231
- @password = t_conf['password']
232
- @port = t_conf['port']
233
- @host = t_conf['host']
234
-
235
- # Preserve everything in options so we can easily create copies of a Target.
236
- @options = t_conf.merge(@options)
237
-
238
- self
239
- end
240
-
241
- def parse(string)
242
- if string.nil?
243
- nil
244
- elsif string =~ %r{^[^:]+://}
245
- Addressable::URI.parse(string)
246
- else
247
- # Initialize with an empty scheme to ensure we parse the hostname correctly
248
- Addressable::URI.parse("//#{string}")
249
- end
250
- rescue Addressable::URI::InvalidURIError => e
251
- raise Bolt::ParseError, "Could not parse target URI: #{e.message}"
252
- end
253
- private :parse
254
-
255
- def features
256
- if @inventory
257
- @inventory.features(self)
258
- else
259
- Set.new
260
- end
261
- end
262
- alias feature_set features
263
-
264
- def plugin_hooks
265
- if @inventory
266
- @inventory.plugin_hooks(self)
267
- else
268
- {}
269
- end
270
- end
271
-
272
- def vars
273
- @inventory.vars(self)
274
- end
275
-
276
- def facts
277
- @inventory.facts(self)
278
- end
279
-
280
- def target_alias
281
- @inventory.target_alias(self)
282
- end
283
-
284
- # TODO: WHAT does equality mean here?
285
- # should we just compare names? is there something else that is meaninful?
286
- def eql?(other)
287
- if self.class.equal?(other.class)
288
- @uri ? @uri == other.uri : @name == other.name
289
- else
290
- false
291
- end
292
- end
293
- alias == eql?
294
-
295
- def hash
296
- @uri.hash ^ @options.hash
297
- end
298
-
299
- def to_s
300
- opts = @options.select { |k, _| PRINT_OPTS.include? k }
301
- "Target('#{@uri}', #{opts})"
302
- end
303
-
304
- def to_h
305
- options.merge(
306
- 'name' => name,
307
- 'uri' => uri,
308
- 'protocol' => protocol,
309
- 'user' => user,
310
- 'password' => password,
311
- 'host' => host,
312
- 'port' => port
313
- )
314
- end
315
-
316
- def detail
317
- {
318
- 'name' => name,
319
- 'alias' => target_alias,
320
- 'config' => {
321
- 'transport' => transport,
322
- transport => options
323
- },
324
- 'vars' => vars,
325
- 'facts' => facts,
326
- 'features' => features.to_a,
327
- 'plugin_hooks' => plugin_hooks
328
- }
329
- end
330
-
331
- def host
332
- @uri_obj&.hostname || @host
333
- end
334
- alias safe_name host
335
-
336
- def name
337
- @name || @uri
338
- end
339
-
340
- def remote?
341
- @uri_obj&.scheme == 'remote' || @protocol == 'remote'
342
- end
343
-
344
- def port
345
- @uri_obj&.port || @port
346
- end
347
-
348
- # transport is separate from protocol for remote targets.
349
- def transport
350
- remote? ? 'remote' : protocol
351
- end
352
-
353
- def protocol
354
- @uri_obj&.scheme || @protocol
355
- end
356
-
357
- def user
358
- Addressable::URI.unencode_component(@uri_obj&.user) || @user
359
- end
360
-
361
- def password
362
- Addressable::URI.unencode_component(@uri_obj&.password) || @password
363
- end
364
- end
365
154
  end