facter 4.0.37 → 4.0.42

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/bin/facter +3 -4
  3. data/lib/facter.rb +163 -23
  4. data/lib/facter/custom_facts/core/execution/base.rb +42 -6
  5. data/lib/facter/custom_facts/util/directory_loader.rb +1 -1
  6. data/lib/facter/facts/aix/disks.rb +1 -1
  7. data/lib/facter/facts/aix/kernel.rb +1 -1
  8. data/lib/facter/facts/aix/kernelmajversion.rb +1 -1
  9. data/lib/facter/facts/aix/kernelrelease.rb +1 -1
  10. data/lib/facter/facts/aix/kernelversion.rb +1 -1
  11. data/lib/facter/facts/aix/os/release.rb +1 -1
  12. data/lib/facter/facts/linux/cloud.rb +15 -0
  13. data/lib/facter/facts/linux/disks.rb +1 -1
  14. data/lib/facter/facts/linux/ec2_metadata.rb +5 -27
  15. data/lib/facter/facts/linux/ec2_userdata.rb +5 -27
  16. data/lib/facter/facts/linux/is_virtual.rb +7 -46
  17. data/lib/facter/facts/linux/virtual.rb +3 -58
  18. data/lib/facter/facts/rhel/os/release.rb +2 -2
  19. data/lib/facter/facts/solaris/disks.rb +1 -1
  20. data/lib/facter/facts_utils/virtual_detector.rb +78 -0
  21. data/lib/facter/framework/cli/cli.rb +84 -36
  22. data/lib/facter/framework/cli/cli_launcher.rb +34 -38
  23. data/lib/facter/framework/config/fact_groups.rb +36 -2
  24. data/lib/facter/framework/core/cache_manager.rb +40 -23
  25. data/lib/facter/framework/core/fact_loaders/fact_loader.rb +14 -11
  26. data/lib/facter/framework/core/options/config_file_options.rb +5 -3
  27. data/lib/facter/framework/core/options/option_store.rb +27 -10
  28. data/lib/facter/framework/logging/logger.rb +3 -11
  29. data/lib/facter/patches/sysfilesystem/sys/statvfs.rb +92 -0
  30. data/lib/facter/resolvers/aix/os_level.rb +27 -0
  31. data/lib/facter/resolvers/cloud.rb +39 -0
  32. data/lib/facter/resolvers/dmi_decode.rb +1 -0
  33. data/lib/facter/resolvers/memory_resolver.rb +12 -14
  34. data/lib/facter/resolvers/networking_linux_resolver.rb +0 -1
  35. data/lib/facter/resolvers/utils/filesystem_helper.rb +3 -1
  36. data/lib/facter/version.rb +1 -1
  37. metadata +7 -4
  38. data/lib/facter/resolvers/aix/os_level_resolver.rb +0 -25
  39. data/lib/facter/resolvers/os_level_resolver.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2ed5162fef26cfbf5bd010cf7737ac8b4856cf59f9f55745d6cfc1bec39781e
4
- data.tar.gz: 761beee20f449b3bbe1e5dc35c0bcd675e9602902804e7add3ee6c3d31a8916d
3
+ metadata.gz: ffa55de7f92a74b84788507b7e9667f158edc68abef1412f40ab5d3beb8f6aad
4
+ data.tar.gz: e92ff5798a9abab30f1887c5e4f934d75cef67975b2485e53ba6dc58b59ee899
5
5
  SHA512:
6
- metadata.gz: 92751ef6452023c4e4edd9c2b7d21bd78bef74404d5550d4de353b4243f6639f29abbba1f00d6f8ba0b4bbf7afbea060f00aa34919a2d1d94459e1df5515e706
7
- data.tar.gz: b4ca79c0907439874ae638a920def98b9ed0d3e2893a77b6bc3d44dfb3cba756f88e550d55d14a8e4cdb9d2c5b58a6d0c6a6c335955ae819607021a80562cd65
6
+ metadata.gz: 4841268cf5f76f1ad2b0ed2bf16b2527dd73e4d41728c64dbe13986b1a574759f900e2748e72ce72f6c677cf754d8a4f5115530140285412a07943e13b6312a5
7
+ data.tar.gz: bd48e0942af375429188957956a5555963297d62a9bc6549529ae1713b7670b41bfc5eea6b894d961e3e32507963e394779c372ad3b12a6422b5218f94b0f9e4
data/bin/facter CHANGED
@@ -4,8 +4,7 @@
4
4
  require 'pathname'
5
5
  require 'facter/framework/cli/cli_launcher.rb'
6
6
 
7
- cli_launcher = CliLauncher.new(ARGV)
7
+ Facter::OptionsValidator.validate(ARGV)
8
+ processed_arguments = CliLauncher.prepare_arguments(ARGV)
8
9
 
9
- cli_launcher.validate_options
10
- cli_launcher.prepare_arguments
11
- cli_launcher.start
10
+ CliLauncher.start(processed_arguments)
@@ -13,8 +13,31 @@ module Facter
13
13
  Options.init
14
14
  Log.output(STDOUT)
15
15
  @already_searched = {}
16
+ @debug_once = []
17
+ @warn_once = []
16
18
 
17
19
  class << self
20
+ def resolve(args_as_string)
21
+ require 'facter/framework/cli/cli_launcher'
22
+
23
+ args = args_as_string.split(' ')
24
+
25
+ Facter::OptionsValidator.validate(args)
26
+ processed_arguments = CliLauncher.prepare_arguments(args, nil)
27
+
28
+ cli = Facter::Cli.new([], processed_arguments)
29
+
30
+ if cli.args.include?(:version)
31
+ cli.invoke(:version, [])
32
+ elsif cli.args.include?('--list-cache-groups')
33
+ cli.invoke(:list_cache_groups, [])
34
+ elsif cli.args.include?('--list-block-groups')
35
+ cli.invoke(:list_block_groups, [])
36
+ else
37
+ cli.invoke(:arg_parser)
38
+ end
39
+ end
40
+
18
41
  def clear_messages
19
42
  logger.debug('clear_messages is not implemented')
20
43
  end
@@ -54,6 +77,8 @@ module Facter
54
77
  # @api public
55
78
  def clear
56
79
  @already_searched = {}
80
+ @debug_once = []
81
+ @warn_once = []
57
82
  LegacyFacter.clear
58
83
  Options[:custom_dir] = []
59
84
  LegacyFacter.collection.invalidate_custom_facts
@@ -68,24 +93,54 @@ module Facter
68
93
  fact_collection.dig(*splitted_user_query)
69
94
  end
70
95
 
71
- # Prints out a debug message when debug option is set to true
72
- # @param msg [String] Message to be printed out
96
+ # Logs debug message when debug option is set to true
97
+ # @param message [Object] Message object to be logged
98
+ #
99
+ # @return [nil]
100
+ #
101
+ # @api public
102
+ def debug(message)
103
+ return unless debugging?
104
+
105
+ logger.debug(message.to_s)
106
+ nil
107
+ end
108
+
109
+ # Logs the same debug message only once when debug option is set to true
110
+ # @param message [Object] Message object to be logged
73
111
  #
74
112
  # @return [nil]
75
113
  #
76
114
  # @api public
77
- def debug(msg)
115
+ def debugonce(message)
78
116
  return unless debugging?
79
117
 
80
- logger.debug(msg)
118
+ message_string = message.to_s
119
+ return if @debug_once.include? message_string
120
+
121
+ @debug_once << message_string
122
+ logger.debug(message_string)
81
123
  nil
82
124
  end
83
125
 
126
+ # Define a new fact or extend an existing fact.
127
+ #
128
+ # @param name [Symbol] The name of the fact to define
129
+ # @param options [Hash] A hash of options to set on the fact
130
+ #
131
+ # @return [Facter::Util::Fact] The fact that was defined
132
+ #
133
+ # @api public
134
+ def define_fact(name, options = {}, &block)
135
+ options[:fact_type] = :custom
136
+ LegacyFacter.define_fact(name, options, &block)
137
+ end
138
+
84
139
  def on_message(&block)
85
140
  Facter::Log.on_message(&block)
86
141
  end
87
142
 
88
- # Check whether debuging is enabled
143
+ # Check whether debugging is enabled
89
144
  #
90
145
  # @return [bool]
91
146
  #
@@ -104,11 +159,31 @@ module Facter
104
159
  Facter::Options[:debug] = debug_bool
105
160
  end
106
161
 
162
+ # Iterates over fact names and values
163
+ #
164
+ # @yieldparam [String] name the fact name
165
+ # @yieldparam [String] value the current value of the fact
166
+ #
167
+ # @return [Facter]
168
+ #
169
+ # @api public
170
+ def each
171
+ log_blocked_facts
172
+ resolved_facts = Facter::FactManager.instance.resolve_facts
173
+ SessionCache.invalidate_all_caches
174
+
175
+ resolved_facts.each do |fact|
176
+ yield(fact.name, fact.value)
177
+ end
178
+
179
+ self
180
+ end
181
+
107
182
  # Returns a fact object by name. If you use this, you still have to
108
183
  # call {Facter::Util::Fact#value `value`} on it to retrieve the actual
109
184
  # value.
110
185
  #
111
- # @param name [String] the name of the fact
186
+ # @param user_query [String] the name of the fact
112
187
  #
113
188
  # @return [Facter::Util::Fact, nil] The fact object, or nil if no fact
114
189
  # is found.
@@ -134,6 +209,16 @@ module Facter
134
209
  nil
135
210
  end
136
211
 
212
+ # Loads all facts
213
+ #
214
+ # @return [nil]
215
+ #
216
+ # @api public
217
+ def loadfacts
218
+ LegacyFacter.loadfacts
219
+ nil
220
+ end
221
+
137
222
  # Register directories to be searched for custom facts. The registered directories
138
223
  # must be absolute paths or they will be ignored.
139
224
  #
@@ -199,7 +284,7 @@ module Facter
199
284
  end
200
285
 
201
286
  # Enable or disable trace
202
- # @param debug_bool [bool] Set trace on debug state
287
+ # @param bool [bool] Set trace on debug state
203
288
  #
204
289
  # @return [type] [description]
205
290
  #
@@ -210,7 +295,7 @@ module Facter
210
295
 
211
296
  # Gets the value for a fact. Returns `nil` if no such fact exists.
212
297
  #
213
- # @param name [String] the fact name
298
+ # @param user_query [String] the fact name
214
299
  # @return [String] the value of the fact, or nil if no fact is found
215
300
  #
216
301
  # @api public
@@ -220,6 +305,18 @@ module Facter
220
305
  @already_searched[user_query]&.value
221
306
  end
222
307
 
308
+ def values(options, user_queries)
309
+ init_cli_options(options, user_queries)
310
+ resolved_facts = Facter::FactManager.instance.resolve_facts(user_queries)
311
+ Facter::SessionCache.invalidate_all_caches
312
+
313
+ if user_queries.count.zero?
314
+ Facter::FactCollection.new.build_fact_collection!(resolved_facts)
315
+ else
316
+ FormatterHelper.retrieve_facts_to_display_for_user_query(user_queries, resolved_facts)
317
+ end
318
+ end
319
+
223
320
  # Returns Facter version
224
321
  #
225
322
  # @return [String] Current version
@@ -247,23 +344,67 @@ module Facter
247
344
  [fact_formatter.format(resolved_facts), status || 0]
248
345
  end
249
346
 
250
- def log_exception(exception, message = :default)
251
- arr = []
252
- if message == :default
253
- arr << exception.message
254
- elsif message
255
- arr << message
256
- end
257
- if Options[:trace]
258
- arr << 'backtrace:'
259
- arr.concat(exception.backtrace)
260
- end
347
+ def log_exception(exception, message = nil)
348
+ error_message = []
349
+
350
+ error_message << message.to_s unless message.nil? || (message.is_a?(String) && message.empty?)
261
351
 
262
- logger.error(arr.flatten.join("\n"))
352
+ parse_exception(exception, error_message)
353
+ logger.error(error_message.flatten.join("\n"))
354
+ end
355
+
356
+ # Returns a list with the names of all solved facts
357
+ #
358
+ # @return [Array] the list with all the fact names
359
+ #
360
+ # @api public
361
+ def list
362
+ to_hash.keys.sort
363
+ end
364
+
365
+ # Logs the message parameter as a warning.
366
+ #
367
+ # @param message [Object] the warning object to be displayed
368
+ #
369
+ # @return [nil]
370
+ #
371
+ # @api public
372
+ def warn(message)
373
+ logger.warn(message.to_s)
374
+ nil
375
+ end
376
+
377
+ # Logs only once the same warning message.
378
+ #
379
+ # @param message [Object] the warning message object
380
+ #
381
+ # @return [nil]
382
+ #
383
+ # @api public
384
+ def warnonce(message)
385
+ message_string = message.to_s
386
+ return if @warn_once.include? message_string
387
+
388
+ @warn_once << message_string
389
+ logger.warn(message_string)
390
+ nil
263
391
  end
264
392
 
265
393
  private
266
394
 
395
+ def parse_exception(exception, error_message)
396
+ if exception.is_a?(Exception)
397
+ error_message << exception.message if error_message.empty?
398
+
399
+ if Options[:trace] && !exception.backtrace.nil?
400
+ error_message << 'backtrace:'
401
+ error_message.concat(exception.backtrace)
402
+ end
403
+ elsif error_message.empty?
404
+ error_message << exception.to_s
405
+ end
406
+ end
407
+
267
408
  def logger
268
409
  @logger ||= Log.new(self)
269
410
  end
@@ -303,10 +444,9 @@ module Facter
303
444
  # Returns exit status when user query contains facts that do
304
445
  # not exist
305
446
  #
306
- # @param dirs [Array] Arguments sent to CLI
307
- # @param dirs [Array] List of resolved facts
447
+ # @param resolved_facts [Array] List of resolved facts
308
448
  #
309
- # @return [Integer, nil] Will return status 1 if user query contains
449
+ # @return [1/nil] Will return status 1 if user query contains
310
450
  # facts that are not found or resolved, otherwise it will return nil
311
451
  #
312
452
  # @api private
@@ -6,6 +6,10 @@ module Facter
6
6
  class Base
7
7
  STDERR_MESSAGE = 'Command %s resulted with the following stderr message: %s'
8
8
 
9
+ def initialize
10
+ @log = Log.new(self)
11
+ end
12
+
9
13
  # This is part of the public API. No race condition can happen
10
14
  # here because custom facts are executed sequentially
11
15
  def with_env(values)
@@ -36,9 +40,7 @@ module Facter
36
40
  end
37
41
 
38
42
  def execute(command, options = {})
39
- on_fail = options.fetch(:on_fail, :raise)
40
- expand = options.fetch(:expand, true)
41
- logger = options[:logger]
43
+ on_fail, expand, logger, time_limit = extract_options(options)
42
44
 
43
45
  expanded_command = if !expand && builtin_command?(command) || logger
44
46
  command
@@ -55,11 +57,21 @@ module Facter
55
57
  return on_fail
56
58
  end
57
59
 
58
- execute_command(expanded_command, on_fail, logger)
60
+ execute_command(expanded_command, on_fail, logger, time_limit)
59
61
  end
60
62
 
61
63
  private
62
64
 
65
+ def extract_options(options)
66
+ on_fail = options.fetch(:on_fail, :raise)
67
+ expand = options.fetch(:expand, true)
68
+ logger = options[:logger]
69
+ time_limit = options[:limit].to_i
70
+ time_limit = time_limit.positive? ? time_limit : nil
71
+
72
+ [on_fail, expand, logger, time_limit]
73
+ end
74
+
63
75
  def log_stderr(msg, command, logger)
64
76
  return if !msg || msg.empty?
65
77
 
@@ -77,12 +89,36 @@ module Facter
77
89
  output.chomp =~ /builtin/ ? true : false
78
90
  end
79
91
 
80
- def execute_command(command, on_fail, logger = nil)
92
+ def execute_command(command, on_fail, logger = nil, time_limit = nil)
93
+ time_limit ||= 300
81
94
  begin
82
95
  # Set LC_ALL and LANG to force i18n to C for the duration of this exec;
83
96
  # this ensures that any code that parses the
84
97
  # output of the command can expect it to be in a consistent / predictable format / locale
85
- out, stderr, _status_ = Open3.capture3({ 'LC_ALL' => 'C', 'LANG' => 'C' }, command.to_s)
98
+ opts = { 'LC_ALL' => 'C', 'LANG' => 'C' }
99
+ require 'timeout'
100
+ @log.debug("Executing command: #{command}")
101
+ out, stderr = Open3.popen3(opts, command.to_s) do |_, stdout, stderr, wait_thr|
102
+ pid = wait_thr.pid
103
+ stdout_messages = +''
104
+ stderr_messages = +''
105
+ out_reader = Thread.new { stdout.read }
106
+ err_reader = Thread.new { stderr.read }
107
+ begin
108
+ Timeout.timeout(time_limit) do
109
+ stdout_messages << out_reader.value
110
+ stderr_messages << err_reader.value
111
+ end
112
+ rescue Timeout::Error
113
+ message = "Timeout encounter after #{time_limit}s, killing process with pid: #{pid}"
114
+ Process.kill('KILL', pid)
115
+ on_fail == :raise ? (raise StandardError, message) : @log.debug(message)
116
+ ensure
117
+ out_reader.kill
118
+ err_reader.kill
119
+ end
120
+ [stdout_messages, stderr_messages]
121
+ end
86
122
  log_stderr(stderr, command, logger)
87
123
  rescue StandardError => e
88
124
  return '' if logger
@@ -59,7 +59,7 @@ module LegacyFacter
59
59
  basename = File.basename(file)
60
60
  next if file_blocked?(basename)
61
61
 
62
- if facts.find { |f| f.name == basename } && cm.group_cached?(basename)
62
+ if facts.find { |f| f.name == basename } && cm.fact_cache_enabled?(basename)
63
63
  Facter.log_exception(Exception.new("Caching is enabled for group \"#{basename}\" while "\
64
64
  'there are at least two external facts files with the same filename'))
65
65
  else
@@ -24,7 +24,7 @@ module Facts
24
24
 
25
25
  def add_legacy_facts(disks, facts)
26
26
  disks.each do |disk_name, disk_info|
27
- facts.push(Facter::ResolvedFact.new("blockdevice_#{disk_name}_size", disk_info[:size_bytes].to_s, :legacy))
27
+ facts.push(Facter::ResolvedFact.new("blockdevice_#{disk_name}_size", disk_info[:size_bytes], :legacy))
28
28
  end
29
29
  end
30
30
  end
@@ -6,7 +6,7 @@ module Facts
6
6
  FACT_NAME = 'kernel'
7
7
 
8
8
  def call_the_resolver
9
- fact_value = Facter::Resolvers::OsLevel.resolve(:kernel)
9
+ fact_value = Facter::Resolvers::Aix::OsLevel.resolve(:kernel)
10
10
 
11
11
  Facter::ResolvedFact.new(FACT_NAME, fact_value)
12
12
  end
@@ -6,7 +6,7 @@ module Facts
6
6
  FACT_NAME = 'kernelmajversion'
7
7
 
8
8
  def call_the_resolver
9
- fact_value = Facter::Resolvers::OsLevel.resolve(:build)
9
+ fact_value = Facter::Resolvers::Aix::OsLevel.resolve(:build)
10
10
  kernelmajversion = fact_value.split('-')[0]
11
11
 
12
12
  Facter::ResolvedFact.new(FACT_NAME, kernelmajversion)
@@ -6,7 +6,7 @@ module Facts
6
6
  FACT_NAME = 'kernelrelease'
7
7
 
8
8
  def call_the_resolver
9
- fact_value = Facter::Resolvers::OsLevel.resolve(:build).strip
9
+ fact_value = Facter::Resolvers::Aix::OsLevel.resolve(:build).strip
10
10
 
11
11
  Facter::ResolvedFact.new(FACT_NAME, fact_value)
12
12
  end
@@ -6,7 +6,7 @@ module Facts
6
6
  FACT_NAME = 'kernelversion'
7
7
 
8
8
  def call_the_resolver
9
- fact_value = Facter::Resolvers::OsLevel.resolve(:build)
9
+ fact_value = Facter::Resolvers::Aix::OsLevel.resolve(:build)
10
10
  kernelversion = fact_value.split('-')[0]
11
11
 
12
12
  Facter::ResolvedFact.new(FACT_NAME, kernelversion)
@@ -8,7 +8,7 @@ module Facts
8
8
  ALIASES = %w[operatingsystemmajrelease operatingsystemrelease].freeze
9
9
 
10
10
  def call_the_resolver
11
- fact_value = Facter::Resolvers::OsLevel.resolve(:build)
11
+ fact_value = Facter::Resolvers::Aix::OsLevel.resolve(:build)
12
12
  major = fact_value.split('-')[0]
13
13
 
14
14
  [Facter::ResolvedFact.new(FACT_NAME, full: fact_value.strip, major: major),