facter 4.0.25 → 4.0.26

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 258f3076e55739266049906ec76f9813481b5289a90e45ba96ad06ff59e4bc8c
4
- data.tar.gz: 5797140df4c3063e3121bf5d9118aa23975c563517181c17263607a27c1939ec
3
+ metadata.gz: d90029b76954a57efa0f989018162ae7f86e26d9b111db2167086de82ef55f57
4
+ data.tar.gz: 65abc86b8335b04f49e533286313e86602050b097140b8462c911cb6cf44b139
5
5
  SHA512:
6
- metadata.gz: f810ad19ee6d8246684844aa388979089d4283ddea1dccb5cbdf3e1116c87f383a194e5ceb88c7c1894578196980271c6b6f0a435edaf89e0b0699e65b6aacc4
7
- data.tar.gz: 828a1dadd8c44eb2dedfd1e6c4b8a1bfc77c05794bcad4e9cae5ad251f3e8a18f85b4b0c9ed6f3cb9be7f3ed6233e3a9d3a33bb34186e9c69be2b51bcad11a3a
6
+ metadata.gz: d94ca6623630e5889c10472cdfd083c3b34ba6f200c8e3ddf1bcdbe16f00a59a674b350e5c2bf0e7f99dd0339a26899bd5a7525096a2b1e36a341e9b2adac116
7
+ data.tar.gz: c0909ade0eab953884e87e4fe731453c1ef60e1fea653ed7d65c4d0891cdc8f75d21221a07e4a68389e1c0f280ecb18975455e1802d1864135c1115c4fc44eed
@@ -5,55 +5,91 @@ def install_bundler
5
5
  run('gem install bundler')
6
6
  end
7
7
 
8
- def install_facter_3_dependecies
8
+ def install_facter_3_dependencies
9
9
  message('INSTALL FACTER 3 ACCEPTANCE DEPENDENCIES')
10
10
  run('bundle install')
11
11
  end
12
12
 
13
- def install_custom_beaker
14
- message('BUILD CUSTOM BEAKER GEM')
15
- run('gem build beaker.gemspec')
16
-
17
- message('INSTALL CUSTOM BEAKER GEM')
18
- run('gem install beaker-*.gem')
13
+ def use_custom_beaker
14
+ message('USE CUSTOM BEAKER')
15
+ beaker_path, _ = run('bundle info beaker --path', FACTER_3_ACCEPTANCE_PATH)
16
+ Dir.chdir(beaker_path.split("\n").last) do
17
+ run('git init')
18
+ run("git remote add origin https://github.com/Filipovici-Andrei/beaker.git")
19
+ run('git fetch')
20
+ run("git reset --hard origin/github_actions")
21
+ end
19
22
  end
20
23
 
21
24
  def initialize_beaker
22
- beaker_options = "#{get_beaker_platform(ENV['ImageOS'].to_sym)}{hypervisor=none\\,hostname=localhost}"
25
+ beaker_platform_with_options = platform_with_options(beaker_platform)
23
26
 
24
27
  message('BEAKER INITIALIZE')
25
- run("beaker init -h #{beaker_options} -o config/aio/options.rb")
28
+ run("beaker init -h #{beaker_platform_with_options} -o #{File.join('config', 'aio', 'options.rb')}")
26
29
 
27
30
  message('BEAKER PROVISION')
28
31
  run('beaker provision')
29
32
  end
30
33
 
31
- def get_beaker_platform(host_platform)
32
- beaker_platforms = {
33
- ubuntu18: 'ubuntu1804-64a',
34
- ubuntu16: 'ubuntu1604-64a',
35
- macos1015: 'osx1015-64a'
36
- }
34
+ def beaker_platform
35
+ {
36
+ 'ubuntu-18.04' => 'ubuntu1804-64a',
37
+ 'ubuntu-16.04' => 'ubuntu1604-64a',
38
+ 'macos-10.15' => 'osx1015-64a',
39
+ 'windows-2016' => 'windows2016-64a',
40
+ 'windows-2019' => 'windows2019-64a'
41
+ }[HOST_PLATFORM]
42
+ end
37
43
 
38
- beaker_platforms[host_platform]
44
+ def platform_with_options(platform)
45
+ return "\"#{platform}{hypervisor=none,hostname=localhost,is_cygwin=false}\"" if platform.include? 'windows'
46
+ "#{platform}{hypervisor=none\\,hostname=localhost}"
39
47
  end
40
48
 
41
49
  def install_puppet_agent
50
+ message('INSTALL PUPPET AGENT')
51
+
42
52
  beaker_puppet_root, _ = run('bundle info beaker-puppet --path')
43
- install_puppet_file_path = File.join(beaker_puppet_root.chomp, 'setup', 'aio', '010_Install_Puppet_Agent.rb')
53
+ presuite_file_path = File.join(beaker_puppet_root.chomp, 'setup', 'aio', '010_Install_Puppet_Agent.rb')
44
54
 
45
- message('INSTALL PUPPET AGENT')
46
- run("beaker exec pre-suite --pre-suite #{install_puppet_file_path}")
55
+ run("beaker exec pre-suite --pre-suite #{presuite_file_path} --preserve-state", './', env_path_var)
47
56
  end
48
57
 
49
- def replace_facter_3_with_facter_4
58
+ def puppet_bin_dir
50
59
  linux_puppet_bin_dir = '/opt/puppetlabs/puppet/bin'
51
- gem_command = File.join(linux_puppet_bin_dir, 'gem')
52
- puppet_command = File.join(linux_puppet_bin_dir, 'puppet')
60
+ windows_puppet_bin_dir = 'C:\\Program Files\\Puppet Labs\\Puppet\\bin'
53
61
 
62
+ (HOST_PLATFORM.include? 'windows') ? windows_puppet_bin_dir : linux_puppet_bin_dir
63
+ end
64
+
65
+ def puppet_command
66
+ return '/opt/puppetlabs/puppet/bin/puppet' unless HOST_PLATFORM.include? 'windows'
67
+ "\"C:\\Program Files\\Puppet Labs\\Puppet\\bin\\puppet\""
68
+ end
69
+
70
+ def gem_command
71
+ return '/opt/puppetlabs/puppet/bin/gem' unless HOST_PLATFORM.include? 'windows'
72
+ "\"C:\\Program Files\\Puppet Labs\\Puppet\\puppet\\bin\\gem\""
73
+ end
74
+
75
+ def env_path_var
76
+ (HOST_PLATFORM.include? 'windows') ? { 'PATH' => "#{puppet_bin_dir};#{ENV['PATH']}" } : {}
77
+ end
78
+
79
+ def replace_facter_3_with_facter_4
54
80
  message('SET FACTER 4 FLAG TO TRUE')
55
81
  run("#{puppet_command} config set facterng true")
56
82
 
83
+ install_latest_facter_4(gem_command)
84
+
85
+ message('CHANGE FACTER 3 WITH FACTER 4')
86
+
87
+ extension = (HOST_PLATFORM.include? 'windows') ? '.bat' : ''
88
+ run("mv facter-ng#{extension} facter#{extension}", puppet_bin_dir)
89
+ end
90
+
91
+
92
+ def install_latest_facter_4(gem_command)
57
93
  message('BUILD FACTER 4 LATEST AGENT GEM')
58
94
  run("#{gem_command} build agent/facter-ng.gemspec", ENV['FACTER_4_ROOT'])
59
95
 
@@ -62,14 +98,12 @@ def replace_facter_3_with_facter_4
62
98
 
63
99
  message('INSTALL FACTER 4 GEM')
64
100
  run("#{gem_command} install -f facter-ng-*.gem", ENV['FACTER_4_ROOT'])
65
-
66
- message('CHANGE FACTER 3 WITH FACTER 4')
67
- run('mv facter-ng facter', linux_puppet_bin_dir)
68
101
  end
69
102
 
70
103
  def run_acceptance_tests
71
104
  message('RUN ACCEPTANCE TESTS')
72
- run('beaker exec tests --test-tag-exclude=server,facter_3 --test-tag-or=risk:high,audit:high')
105
+
106
+ run('beaker exec tests --test-tag-exclude=server,facter_3 --test-tag-or=risk:high,audit:high', './', env_path_var)
73
107
  end
74
108
 
75
109
  def message(message)
@@ -80,21 +114,28 @@ def message(message)
80
114
  puts "\n\n#{result}\n\n"
81
115
  end
82
116
 
83
- def run(command, dir = './')
117
+ def run(command, dir = './', env = {})
84
118
  puts command
85
- output, status = Open3.capture2(command, chdir: dir)
86
- puts output
119
+ output = ''
120
+ status = 0
121
+ Open3.popen2e(env, command, chdir: dir) do |_stdin, stdout_and_err, wait_thr|
122
+ stdout_and_err.each do |line|
123
+ puts line
124
+ output += line
125
+ end
126
+ status = wait_thr.value
127
+ end
87
128
  [output, status]
88
129
  end
89
130
 
90
- ENV['DEBIAN_DISABLE_RUBYGEMS_INTEGRATION'] = 'no_wornings'
131
+ ENV['DEBIAN_DISABLE_RUBYGEMS_INTEGRATION'] = 'no_warnings'
91
132
  FACTER_3_ACCEPTANCE_PATH = File.join(ENV['FACTER_3_ROOT'], 'acceptance')
133
+ HOST_PLATFORM = ARGV[0]
92
134
 
93
135
  install_bundler
94
136
 
95
- Dir.chdir(FACTER_3_ACCEPTANCE_PATH) { install_facter_3_dependecies }
96
-
97
- Dir.chdir(ENV['BEAKER_ROOT']) { install_custom_beaker }
137
+ Dir.chdir(FACTER_3_ACCEPTANCE_PATH) { install_facter_3_dependencies }
138
+ use_custom_beaker
98
139
 
99
140
  Dir.chdir(FACTER_3_ACCEPTANCE_PATH) do
100
141
  initialize_beaker
@@ -14,14 +14,12 @@ jobs:
14
14
  name: Platform
15
15
  strategy:
16
16
  matrix:
17
- os: [ubuntu-18.04, ubuntu-16.04, macos-10.15]
17
+ os: [windows-2016, windows-2019, ubuntu-16.04, ubuntu-18.04, macos-10.15]
18
18
  runs-on: ${{ matrix.os }}
19
19
  env:
20
20
  FACTER_3_ROOT: facter_3
21
21
  FACTER_4_ROOT: facter_4
22
- BEAKER_ROOT: beaker
23
22
  SHA: latest
24
- BEAKER_VERSION: 4.21.0
25
23
 
26
24
  steps:
27
25
  - name: Checkout current PR
@@ -33,22 +31,16 @@ jobs:
33
31
  uses: actions/checkout@v2
34
32
  with:
35
33
  repository: puppetlabs/facter
36
- ref: skip_failures_on_ng
34
+ ref: windows_github
37
35
  path: facter_3
38
36
 
39
- - name: Clone custom beaker fork
40
- uses: actions/checkout@v2
41
- with:
42
- repository: mihaibuzgau/beaker
43
- ref: master
44
- path: beaker
45
-
46
37
  - name: Install Ruby 2.6
47
38
  uses: ruby/setup-ruby@v1
48
39
  with:
49
40
  ruby-version: '2.6'
50
41
 
51
- - name: Fix common permissions
42
+ - name: Fix common Linux and MacOs permissions
43
+ if: runner.os != 'Windows'
52
44
  run: sudo chmod a-w /opt
53
45
 
54
46
  - name: Fix Linux permissions
@@ -57,11 +49,17 @@ jobs:
57
49
  sudo chmod a-w /home/runner /usr/share &&
58
50
  sudo chmod -R a-w /usr/share/rust /home/runner/.config /home/linuxbrew
59
51
 
60
- - name: Instal dhclient
52
+ - name: Instal dhclient for Linux
61
53
  if: runner.os == 'Linux'
62
54
  run: |
63
55
  sudo apt install dhcpcd5
64
56
  sudo dhclient
65
57
 
66
- - name: Run acceptance tests
67
- run: sudo -E "PATH=$PATH" ruby facter_4/.github/actions/presuite.rb
58
+ - name: Run acceptance tests on Linux like platform
59
+ if: runner.os != 'Windows'
60
+ run: sudo -E "PATH=$PATH" ruby $FACTER_4_ROOT/.github/actions/presuite.rb ${{ matrix.os }}
61
+
62
+ - name: Run acceptance tests on Windows like platform
63
+ if: runner.os == 'Windows'
64
+ run: ruby $Env:FACTER_4_ROOT/.github/actions/presuite.rb ${{ matrix.os }}
65
+
@@ -37,35 +37,12 @@ jobs:
37
37
  steps:
38
38
  - name: Checkout current PR
39
39
  uses: actions/checkout@v2
40
-
41
- - name: Commit message checks
42
- uses: ruby/setup-ruby@v1
43
40
  with:
44
- ruby-version: 2.6
45
- - run: bundle install --jobs 3 --retry 3
46
- - run: bundle exec rake commits
47
-
48
- coverage_checks:
49
- runs-on: ubuntu-18.04
50
- name: coverage
51
- steps:
52
- - name: Checkout current PR
53
- uses: actions/checkout@v2
54
-
55
- - name: Setup Code Climate test-reporter
56
- run: |
57
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
58
- chmod +x ./cc-test-reporter
59
- ./cc-test-reporter before-build
41
+ fetch-depth: 2
60
42
 
61
43
  - name: Commit message checks
62
44
  uses: ruby/setup-ruby@v1
63
45
  with:
64
46
  ruby-version: 2.6
65
47
  - run: bundle install --jobs 3 --retry 3
66
- - run: bundle exec rake spec
67
-
68
- - name: Publish code coverage
69
- run: |
70
- export GIT_BRANCH="${GITHUB_REF/refs\/heads\//}"
71
- ./cc-test-reporter after-build -r ${{secrets.CC_TEST_REPORTER_ID}}
48
+ - run: bundle exec rake commits
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: Coverage
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - master
8
+
9
+ jobs:
10
+ coverage_checks:
11
+ runs-on: ubuntu-18.04
12
+ name: coverage
13
+ steps:
14
+ - name: Checkout current PR
15
+ uses: actions/checkout@v2
16
+
17
+ - name: Setup Code Climate test-reporter
18
+ run: |
19
+ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
20
+ chmod +x ./cc-test-reporter
21
+ ./cc-test-reporter before-build
22
+
23
+ - name: Generate coverage
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: 2.6
27
+ - run: bundle install --jobs 3 --retry 3
28
+ - run: bundle exec rake spec
29
+
30
+ - name: Publish code coverage
31
+ run: |
32
+ export GIT_BRANCH="${GITHUB_REF/refs\/heads\//}"
33
+ ./cc-test-reporter after-build -r ${{secrets.CC_TEST_REPORTER_ID}}
@@ -24,6 +24,7 @@ jobs:
24
24
  uses: ruby/setup-ruby@v1
25
25
  with:
26
26
  ruby-version: ${{ matrix.ruby }}
27
+ - run: gem update bundler
27
28
  - run: bundle install --jobs 3 --retry 3
28
29
  - run: bundle exec rake spec
29
30
 
@@ -37,5 +38,6 @@ jobs:
37
38
  uses: ruby/setup-ruby@v1
38
39
  with:
39
40
  ruby-version: 2.7
41
+ - run: gem update bundler
40
42
  - run: bundle install --jobs 3 --retry 3
41
43
  - run: bundle exec rake spec
@@ -129,7 +129,6 @@ RSpec/MessageSpies:
129
129
  - 'spec/custom_facts/util/loader_spec.rb'
130
130
  - 'spec/custom_facts/util/parser_spec.rb'
131
131
  - 'spec/custom_facts/util/resolution_spec.rb'
132
- - 'spec/facter/facter_spec.rb'
133
132
  - 'spec/facter/facts/aix/os/name_spec.rb'
134
133
  - 'spec/facter/facts/aix/os/release_spec.rb'
135
134
  - 'spec/facter/facts/macosx/is_virtual_spec.rb'
@@ -188,7 +187,6 @@ RSpec/VerifiedDoubles:
188
187
  - 'spec/custom_facts/util/directory_loader_spec.rb'
189
188
  - 'spec/custom_facts/util/fact_spec.rb'
190
189
  - 'spec/custom_facts/util/resolution_spec.rb'
191
- - 'spec/facter/facter_spec.rb'
192
190
  - 'spec/facter/facts/aix/ssh_spec.rb'
193
191
  - 'spec/facter/facts/macosx/memory/swap/capacity_spec.rb'
194
192
  - 'spec/facter/facts/macosx/memory/swap/used_bytes_spec.rb'
@@ -1,5 +1,26 @@
1
1
 
2
2
 
3
+ ## [4.0.26](https://github.com/puppetlabs/facter-ng/tree/4.0.26) (2020-06-11)
4
+
5
+ [Full Changelog](https://github.com/puppetlabs/facter-ng/compare/4.0.25...4.0.26)
6
+
7
+ ### Added
8
+
9
+ - \(FACT-2608\) Add is\_virtual fact [\#535](https://github.com/puppetlabs/facter-ng/pull/535) ([oanatmaria](https://github.com/oanatmaria))
10
+ - \(FACT-2609\) Add lspci resolver [\#534](https://github.com/puppetlabs/facter-ng/pull/534) ([oanatmaria](https://github.com/oanatmaria))
11
+ - \(FACT-2245\) Add xen resolver [\#532](https://github.com/puppetlabs/facter-ng/pull/532) ([oanatmaria](https://github.com/oanatmaria))
12
+ - \(FACT-2607\) Add Openvz detector [\#531](https://github.com/puppetlabs/facter-ng/pull/531) ([oanatmaria](https://github.com/oanatmaria))
13
+ - \(FACT-2600\) Run acceptance tests on Windows [\#519](https://github.com/puppetlabs/facter-ng/pull/519) ([Filipovici-Andrei](https://github.com/Filipovici-Andrei))
14
+
15
+ ### Fixed
16
+
17
+ - \(FACT-2651\) Fix --list-cache-groups when there are multiple arguments before it [\#545](https://github.com/puppetlabs/facter-ng/pull/545) ([IrimieBogdan](https://github.com/IrimieBogdan))
18
+ - FACT-2650 Fix bug when loading external facts [\#543](https://github.com/puppetlabs/facter-ng/pull/543) ([Filipovici-Andrei](https://github.com/Filipovici-Andrei))
19
+ - Use proper encoding [\#539](https://github.com/puppetlabs/facter-ng/pull/539) ([faucct](https://github.com/faucct))
20
+ - \(FACT-2635\) Incorrect output for non existing fact [\#536](https://github.com/puppetlabs/facter-ng/pull/536) ([IrimieBogdan](https://github.com/IrimieBogdan))
21
+
22
+
23
+
3
24
  ## [4.0.25](https://github.com/puppetlabs/facter-ng/tree/4.0.25) (2020-05-29)
4
25
 
5
26
  [Full Changelog](https://github.com/puppetlabs/facter-ng/compare/4.0.24...4.0.25)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.0.25
1
+ 4.0.26
data/bin/facter CHANGED
@@ -4,3 +4,9 @@
4
4
  require 'pathname'
5
5
  ROOT_DIR = Pathname.new(File.expand_path('..', __dir__)) unless defined?(ROOT_DIR)
6
6
  require "#{ROOT_DIR}/lib/framework/cli/cli_launcher.rb"
7
+
8
+ cli_launcher = CliLauncher.new(ARGV)
9
+
10
+ cli_launcher.validate_options
11
+ cli_launcher.prepare_arguments
12
+ cli_launcher.start
@@ -39,6 +39,8 @@ module LegacyFacter
39
39
 
40
40
  paths = search_path
41
41
  paths&.each do |dir|
42
+ # clean the search path of wrong slashes and backslashes
43
+ dir = dir.gsub(%r{[\/\\]+}, File::SEPARATOR)
42
44
  # dir is already an absolute path
43
45
  Dir.glob(File.join(dir, '*.rb')).each do |path|
44
46
  # exclude dirs that end with .rb
@@ -245,7 +245,7 @@ module Facter
245
245
  SessionCache.invalidate_all_caches
246
246
  fact_formatter = Facter::FormatterFactory.build(Facter::Options.get)
247
247
 
248
- status = error_check(args, resolved_facts)
248
+ status = error_check(resolved_facts)
249
249
 
250
250
  [fact_formatter.format(resolved_facts), status || 0]
251
251
  end
@@ -289,6 +289,9 @@ module Facter
289
289
  user_query = user_query.to_s
290
290
  resolved_facts = Facter::FactManager.instance.resolve_facts([user_query])
291
291
  SessionCache.invalidate_all_caches
292
+ # we must make a distinction between custom facts that return nil and nil facts
293
+ # Nil facts should not be packaged as ResolvedFacts! (add_fact_to_searched_facts packages facts)
294
+ resolved_facts = resolved_facts.reject { |fact| fact.type == :nil }
292
295
  fact_collection = FactCollection.new.build_fact_collection!(resolved_facts)
293
296
  splitted_user_query = Facter::Utils.split_user_query(user_query)
294
297
 
@@ -310,9 +313,10 @@ module Facter
310
313
  # facts that are not found or resolved, otherwise it will return nil
311
314
  #
312
315
  # @api private
313
- def error_check(args, resolved_facts)
316
+ def error_check(resolved_facts)
314
317
  if Options[:strict]
315
- missing_names = args - resolved_facts.map(&:user_query).uniq
318
+ missing_names = resolved_facts.select { |fact| fact.type == :nil }.map(&:user_query)
319
+
316
320
  if missing_names.count.positive?
317
321
  status = 1
318
322
  log_errors(missing_names)
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Linux
5
+ class IsVirtual
6
+ FACT_NAME = 'is_virtual'
7
+ HYPERVISORS_HASH = { 'VMware' => 'vmware', 'VirtualBox' => 'virtualbox', 'Parallels' => 'parallels',
8
+ 'KVM' => 'kvm', 'Virtual Machine' => 'hyperv', 'RHEV Hypervisor' => 'rhev',
9
+ 'oVirt Node' => 'ovirt', 'HVM domU' => 'xenhvm', 'Bochs' => 'bochs', 'OpenBSD' => 'vmm',
10
+ 'BHYVE' => 'bhyve' }.freeze
11
+ PHYSICAL_HYPERVISORS = %w[physical xen0 vmware_server vmware_workstation openvzhn vserver_host].freeze
12
+
13
+ def call_the_resolver # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
14
+ fact_value = check_docker_lxc || check_gce || retrieve_from_virt_what || check_vmware
15
+ fact_value ||= check_open_vz || check_vserver || check_xen || check_other_facts || check_lspci || 'physical'
16
+
17
+ Facter::ResolvedFact.new(FACT_NAME, check_if_virtual(fact_value))
18
+ end
19
+
20
+ def check_gce
21
+ bios_vendor = Facter::Resolvers::Linux::DmiBios.resolve(:bios_vendor)
22
+ 'gce' if bios_vendor&.include?('Google')
23
+ end
24
+
25
+ def check_docker_lxc
26
+ Facter::Resolvers::DockerLxc.resolve(:vm)
27
+ end
28
+
29
+ def check_vmware
30
+ Facter::Resolvers::Vmware.resolve(:vm)
31
+ end
32
+
33
+ def retrieve_from_virt_what
34
+ Facter::Resolvers::VirtWhat.resolve(:vm)
35
+ end
36
+
37
+ def check_open_vz
38
+ Facter::Resolvers::OpenVz.resolve(:vm)
39
+ end
40
+
41
+ def check_vserver
42
+ Facter::Resolvers::VirtWhat.resolve(:vserver)
43
+ end
44
+
45
+ def check_xen
46
+ Facter::Resolvers::Xen.resolve(:vm)
47
+ end
48
+
49
+ def check_other_facts
50
+ product_name = Facter::Resolvers::Linux::DmiBios.resolve(:product_name)
51
+ bios_vendor = Facter::Resolvers::Linux::DmiBios.resolve(:bios_vendor)
52
+ return 'kvm' if bios_vendor&.include?('Amazon EC2')
53
+ return unless product_name
54
+
55
+ HYPERVISORS_HASH.each { |key, value| return value if product_name.include?(key) }
56
+ end
57
+
58
+ def check_lspci
59
+ Facter::Resolvers::Lspci.resolve(:vm)
60
+ end
61
+
62
+ def check_if_virtual(found_vm)
63
+ PHYSICAL_HYPERVISORS.count(found_vm).zero?
64
+ end
65
+ end
66
+ end
67
+ end
@@ -4,9 +4,14 @@ module Facts
4
4
  module Linux
5
5
  class Virtual
6
6
  FACT_NAME = 'virtual'
7
+ HYPERVISORS_HASH = { 'VMware' => 'vmware', 'VirtualBox' => 'virtualbox', 'Parallels' => 'parallels',
8
+ 'KVM' => 'kvm', 'Virtual Machine' => 'hyperv', 'RHEV Hypervisor' => 'rhev',
9
+ 'oVirt Node' => 'ovirt', 'HVM domU' => 'xenhvm', 'Bochs' => 'bochs', 'OpenBSD' => 'vmm',
10
+ 'BHYVE' => 'bhyve' }.freeze
7
11
 
8
- def call_the_resolver
12
+ def call_the_resolver # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
9
13
  fact_value = check_docker_lxc || check_gce || retrieve_from_virt_what || check_vmware
14
+ fact_value ||= check_open_vz || check_vserver || check_xen || check_other_facts || check_lspci || 'physical'
10
15
 
11
16
  Facter::ResolvedFact.new(FACT_NAME, fact_value)
12
17
  end
@@ -27,6 +32,31 @@ module Facts
27
32
  def retrieve_from_virt_what
28
33
  Facter::Resolvers::VirtWhat.resolve(:vm)
29
34
  end
35
+
36
+ def check_open_vz
37
+ Facter::Resolvers::OpenVz.resolve(:vm)
38
+ end
39
+
40
+ def check_vserver
41
+ Facter::Resolvers::VirtWhat.resolve(:vserver)
42
+ end
43
+
44
+ def check_xen
45
+ Facter::Resolvers::Xen.resolve(:vm)
46
+ end
47
+
48
+ def check_other_facts
49
+ product_name = Facter::Resolvers::Linux::DmiBios.resolve(:product_name)
50
+ bios_vendor = Facter::Resolvers::Linux::DmiBios.resolve(:bios_vendor)
51
+ return 'kvm' if bios_vendor&.include?('Amazon EC2')
52
+ return unless product_name
53
+
54
+ HYPERVISORS_HASH.each { |key, value| return value if product_name.include?(key) }
55
+ end
56
+
57
+ def check_lspci
58
+ Facter::Resolvers::Lspci.resolve(:vm)
59
+ end
30
60
  end
31
61
  end
32
62
  end
@@ -7,13 +7,53 @@ Facter::Log.output(STDERR)
7
7
  require "#{ROOT_DIR}/lib/facter"
8
8
  require "#{ROOT_DIR}/lib/framework/cli/cli"
9
9
 
10
- Facter::OptionsValidator.validate(ARGV)
11
- ARGV.unshift(Facter::Cli.default_task) unless
12
- Facter::Cli.all_tasks.key?(ARGV[0]) ||
13
- Facter::Cli.instance_variable_get(:@map).key?(ARGV[0])
14
-
15
- begin
16
- Facter::Cli.start(ARGV, debug: true)
17
- rescue Thor::UnknownArgumentError => e
18
- Facter::OptionsValidator.write_error_and_exit("unrecognised option '#{e.unknown.first}'")
10
+ class CliLauncher
11
+ def initialize(args)
12
+ @args = args
13
+ end
14
+
15
+ def validate_options
16
+ Facter::OptionsValidator.validate(@args)
17
+ end
18
+
19
+ def prepare_arguments
20
+ @args.unshift(Facter::Cli.default_task) unless
21
+ check_if_arguments_is_known(Facter::Cli.all_tasks, @args) ||
22
+ check_if_arguments_is_known(Facter::Cli.instance_variable_get(:@map), @args)
23
+
24
+ @args = reorder_program_arguments(@args)
25
+ end
26
+
27
+ def start
28
+ Facter::Cli.start(@args, debug: true)
29
+ rescue Thor::UnknownArgumentError => e
30
+ Facter::OptionsValidator.write_error_and_exit("unrecognised option '#{e.unknown.first}'")
31
+ end
32
+
33
+ private
34
+
35
+ def check_if_arguments_is_known(known_arguments, program_arguments)
36
+ program_arguments.each do |argument|
37
+ return true if known_arguments.key?(argument)
38
+ end
39
+
40
+ false
41
+ end
42
+
43
+ def reorder_program_arguments(program_arguments)
44
+ priority_arguments = Facter::Cli.instance_variable_get(:@map)
45
+
46
+ priority_args = []
47
+ normal_args = []
48
+
49
+ program_arguments.each do |argument|
50
+ if priority_arguments.include?(argument)
51
+ priority_args << argument
52
+ else
53
+ normal_args << argument
54
+ end
55
+ end
56
+
57
+ priority_args.concat(normal_args)
58
+ end
19
59
  end
@@ -5,11 +5,13 @@ module Facter
5
5
  @@log = Facter::Log.new(self)
6
6
 
7
7
  def resolve_facts(searched_facts)
8
- searched_facts = filter_internal_facts(searched_facts)
8
+ internal_searched_facts = filter_internal_facts(searched_facts)
9
+ threads = start_threads(internal_searched_facts)
10
+ resolved_facts = join_threads(threads, internal_searched_facts)
9
11
 
10
- threads = start_threads(searched_facts)
12
+ nil_resolved_facts = resolve_nil_facts(searched_facts)
11
13
 
12
- join_threads(threads, searched_facts)
14
+ resolved_facts.concat(nil_resolved_facts)
13
15
  end
14
16
 
15
17
  private
@@ -18,6 +20,15 @@ module Facter
18
20
  searched_facts.select { |searched_fact| %i[core legacy].include? searched_fact.type }
19
21
  end
20
22
 
23
+ def resolve_nil_facts(searched_facts)
24
+ resolved_facts = []
25
+ searched_facts.select { |fact| fact.type == :nil }.each do |fact|
26
+ resolved_facts << ResolvedFact.new(fact.name, nil, :nil, fact.name)
27
+ end
28
+
29
+ resolved_facts
30
+ end
31
+
21
32
  def start_threads(searched_facts)
22
33
  threads = []
23
34
  # only resolve a fact once, even if multiple search facts depend on that fact
@@ -60,7 +60,7 @@ module Facter
60
60
  pretty_json = JSON.pretty_generate(facts_hash)
61
61
 
62
62
  @log.debug('Change key value delimiter from : to =>')
63
- pretty_json.gsub!(/^(.*?)(:)/, '\1 =>')
63
+ pretty_json.gsub!(/":/, '" =>')
64
64
 
65
65
  @log.debug('Remove quotes from parent nodes')
66
66
  pretty_json.gsub!(/\"(.*)\"\ =>/, '\1 =>')
@@ -84,8 +84,10 @@ module Facter
84
84
  end
85
85
 
86
86
  def remove_comma_and_quation(output)
87
+ # quotation marks that come after \ are not removed
87
88
  @log.debug('Remove unnecessary comma and quotation marks on root facts')
88
- output.split("\n").map! { |line| line =~ /^[\s]+/ ? line : line.gsub(/,$|\"/, '') }.join("\n")
89
+ output.split("\n")
90
+ .map! { |line| line =~ /^[\s]+/ ? line : line.gsub(/,$|(?<!\\)\"/, '').gsub('\\"', '"') }.join("\n")
89
91
  end
90
92
  end
91
93
  end
@@ -50,6 +50,8 @@ module Facter
50
50
  return resolvable_fact_list if resolvable_fact_list.any?
51
51
  end
52
52
 
53
+ resolvable_fact_list << SearchedFact.new(query, nil, [], query, :nil) if resolvable_fact_list.empty?
54
+
53
55
  resolvable_fact_list
54
56
  end
55
57
 
@@ -73,9 +75,11 @@ module Facter
73
75
  def found_fact?(fact_name, query_fact)
74
76
  fact_with_wildcard = fact_name.include?('.*') && !query_fact.include?('.')
75
77
 
78
+ processed_equery_fact = query_fact.gsub('\\', '\\\\\\\\')
79
+
76
80
  return false if fact_with_wildcard && !query_fact.match("^#{fact_name}$")
77
81
 
78
- return false unless fact_with_wildcard || fact_name.match("^#{query_fact}($|\\.)")
82
+ return false unless fact_with_wildcard || fact_name.match("^#{processed_equery_fact}($|\\.)")
79
83
 
80
84
  true
81
85
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Resolvers
5
+ class Lspci < BaseResolver
6
+ @semaphore = Mutex.new
7
+ @fact_list ||= {}
8
+
9
+ REGEX_VALUES = { 'VirtualBox' => 'virtualbox', 'XenSource' => 'xenhvm',
10
+ 'Microsoft Corporation Hyper-V' => 'hyperv', 'Class 8007: Google, Inc' => 'gce',
11
+ 'VM[wW]are' => 'vmware', '1ab8:' => 'parallels', '[Pp]arallels' => 'parallels',
12
+ '(?i)(virtio)' => 'kvm' }.freeze
13
+
14
+ class << self
15
+ private
16
+
17
+ def post_resolve(fact_name)
18
+ @fact_list.fetch(fact_name) { lspci_command(fact_name) }
19
+ end
20
+
21
+ def lspci_command(fact_name)
22
+ output = Facter::Core::Execution.execute('lspci', logger: log)
23
+ return if output.empty?
24
+
25
+ @fact_list[:vm] = retrieve_vm(output)
26
+ @fact_list[fact_name]
27
+ end
28
+
29
+ def retrieve_vm(output)
30
+ output.each_line { |line| REGEX_VALUES.each { |key, value| return value if line =~ /#{key}/ } }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -44,7 +44,7 @@ module Facter
44
44
  log.debug 'Executing command: system_profiler SPSoftwareDataType SPHardwareDataType'
45
45
  output = Facter::Core::Execution.execute(
46
46
  'system_profiler SPHardwareDataType SPSoftwareDataType', logger: log
47
- )
47
+ ).force_encoding('UTF-8')
48
48
  @fact_list = output.scan(/.*:[ ].*$/).map { |e| e.strip.match(/(.*?): (.*)/).captures }.to_h
49
49
  normalize_factlist
50
50
 
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Resolvers
5
+ class OpenVz < BaseResolver
6
+ # build
7
+
8
+ @semaphore = Mutex.new
9
+ @fact_list ||= {}
10
+
11
+ class << self
12
+ private
13
+
14
+ def post_resolve(fact_name)
15
+ @fact_list.fetch(fact_name) { check_proc_vz(fact_name) }
16
+ end
17
+
18
+ def check_proc_vz(fact_name)
19
+ if !Dir.exist?('/proc/vz') || !File.executable?('/proc/lve/list') || Dir.entries('/proc/vz').count.equal?(2)
20
+ return
21
+ end
22
+
23
+ @fact_list[:vm] = read_proc_status
24
+ @fact_list[fact_name]
25
+ end
26
+
27
+ def read_proc_status
28
+ proc_status_content = Facter::Util::FileHelper.safe_readlines('/proc/self/status', nil)
29
+ return unless proc_status_content
30
+
31
+ proc_status_content.each do |line|
32
+ parts = line.split("\s")
33
+ next unless parts.size.equal?(2)
34
+
35
+ next unless /^envID:/ =~ parts[0]
36
+
37
+ return 'openvzhn' if parts[1] == '0'
38
+
39
+ return 'openvzve'
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facter
4
+ module Resolvers
5
+ class Xen < BaseResolver
6
+ @semaphore = Mutex.new
7
+ @fact_list ||= {}
8
+
9
+ class << self
10
+ private
11
+
12
+ def post_resolve(fact_name)
13
+ @fact_list.fetch(fact_name) { chech_xen_dirs(fact_name) }
14
+ end
15
+
16
+ def chech_xen_dirs(fact_name)
17
+ xen_type = 'xen0' if File.exist?('/dev/xen/evtchn')
18
+ xen_type = 'xenu' if !xen_type && (File.exist?('/proc/xen') || File.exist?('/dev/xvda1'))
19
+
20
+ @fact_list[:vm] = xen_type
21
+ @fact_list[fact_name]
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -8,12 +8,12 @@ task(:commits) do
8
8
  # populated with the range of commits the PR contains. If not available, this
9
9
  # falls back to `master..HEAD` as a next best bet as `master` is unlikely to
10
10
  # ever be absent.
11
- commit_range = ENV['TRAVIS_COMMIT_RANGE'].nil? ? 'master..HEAD' : ENV['TRAVIS_COMMIT_RANGE'].sub(/\.\.\./, '..')
11
+ commit_range = 'HEAD^..HEAD'
12
12
  puts "Checking commits #{commit_range}"
13
13
  `git log --no-merges --pretty=%s #{commit_range}`.each_line do |commit_summary|
14
14
  # This regex tests for the currently supported commit summary tokens: maint, doc, gem, or fact-<number>.
15
15
  # The exception tries to explain it in more full.
16
- if /^\((maint|doc|docs|gem|fact-\d+)\)|revert/i.match(commit_summary).nil?
16
+ if /^\((maint|doc|docs|gem|fact-\d+)\)|revert|merge/i.match(commit_summary).nil?
17
17
  raise "\n\n\n\tThis commit summary didn't match CONTRIBUTING.md guidelines:\n" \
18
18
  "\n\t\t#{commit_summary}\n" \
19
19
  "\tThe commit summary (i.e. the first line of the commit message) should start with one of:\n" \
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facter
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.25
4
+ version: 4.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-29 00:00:00.000000000 Z
11
+ date: 2020-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -182,6 +182,7 @@ files:
182
182
  - ".github/actions/presuite.rb"
183
183
  - ".github/workflows/acceptance_tests.yml"
184
184
  - ".github/workflows/checks.yaml"
185
+ - ".github/workflows/coverage.yaml"
185
186
  - ".github/workflows/unit_tests.yaml"
186
187
  - ".gitignore"
187
188
  - ".jrubyrc"
@@ -321,6 +322,7 @@ files:
321
322
  - lib/facts/linux/interfaces.rb
322
323
  - lib/facts/linux/ipaddress6_interfaces.rb
323
324
  - lib/facts/linux/ipaddress_interfaces.rb
325
+ - lib/facts/linux/is_virtual.rb
324
326
  - lib/facts/linux/kernel.rb
325
327
  - lib/facts/linux/kernelmajversion.rb
326
328
  - lib/facts/linux/kernelrelease.rb
@@ -694,6 +696,7 @@ files:
694
696
  - lib/resolvers/load_averages_resolver.rb
695
697
  - lib/resolvers/lpar_resolver.rb
696
698
  - lib/resolvers/lsb_release_resolver.rb
699
+ - lib/resolvers/lspci.rb
697
700
  - lib/resolvers/macosx/dmi_resolver.rb
698
701
  - lib/resolvers/macosx/filesystems_resolver.rb
699
702
  - lib/resolvers/macosx/ipaddress_resolver.rb
@@ -706,6 +709,7 @@ files:
706
709
  - lib/resolvers/memory_resolver.rb
707
710
  - lib/resolvers/mountpoints_resolver.rb
708
711
  - lib/resolvers/networking_linux_resolver.rb
712
+ - lib/resolvers/open_vz.rb
709
713
  - lib/resolvers/os_level_resolver.rb
710
714
  - lib/resolvers/os_release_resolver.rb
711
715
  - lib/resolvers/partitions.rb
@@ -765,6 +769,7 @@ files:
765
769
  - lib/resolvers/windows/virtualization_resolver.rb
766
770
  - lib/resolvers/windows/win_os_description_resolver.rb
767
771
  - lib/resolvers/wpar_resolver.rb
772
+ - lib/resolvers/xen.rb
768
773
  - lib/util/api_debugger.rb
769
774
  - lib/util/file_helper.rb
770
775
  - os_hierarchy.json