facter 4.0.25 → 4.0.26

Sign up to get free protection for your applications and to get access to all the features.
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