diff --git a/.travis.yml b/.travis.yml index ab02756..fd31a67 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,19 @@ language: ruby -sudo: required +version: ~> 1.0 +os: linux +sudo: false +bundler_args: --without development system_tests --path vendor + +addons: + apt: + packages: + # provides unbuffer + - expect-dev + - libaugeas-dev + - augeas-tools + rvm: - - 2.4.4 + - 2.5.8 notifications: email: - raphael.pinson@camptocamp.com @@ -11,15 +23,13 @@ env: - PUPPET=5.5 RUBY_AUGEAS=0.5 FORGE_PUBLISH=true # Test latest Puppet version - PUPPET=6 RUBY_AUGEAS=0.5 - + - PUPPET=7 RUBY_AUGEAS=0.5 matrix: fast_finish: true -install: - - "travis_retry ./.travis.sh" script: - - AUGEAS_LENS_LIB=lib/augeas/lenses:augeas/lenses bundle exec rake + - AUGEAS_LENS_LIB=lib/augeas/lenses:augeas/lenses travis_wait 45 unbuffer bundle exec rake # Do not include the augeas/ directory in the deployed module - rm -rf augeas/ deploy: diff --git a/README.md b/README.md index 04f8fc8..dbe2066 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,9 @@ normal. See [Puppet/Augeas pre-requisites](http://docs.puppetlabs.com/guides/augeas.html#pre-requisites). +**WARNING** Your system must be able to run the grub mkconfig scripts with BLS +support if you are on a systen that uses BLS! + ## Installing On Puppet 2.7.14+, the module can be installed easily ([documentation](http://docs.puppetlabs.com/puppet/latest/reference/modules_installing.html)): diff --git a/lib/puppet/provider/grub_config/grub2.rb b/lib/puppet/provider/grub_config/grub2.rb index b3e501c..67e2e28 100644 --- a/lib/puppet/provider/grub_config/grub2.rb +++ b/lib/puppet/provider/grub_config/grub2.rb @@ -78,29 +78,9 @@ def value=(newval) end def flush - os_info = Facter.value(:os) - if os_info - os_name = Facter.value(:os)['name'] - else - # Support for old versions of Facter - unless os_name - os_name = Facter.value(:operatingsystem) - end - end - - cfg = nil - [ - "/etc/grub2-efi.cfg", - # Handle the standard EFI naming convention - "/boot/efi/EFI/#{os_name.downcase}/grub.cfg", - "/boot/grub2/grub.cfg", - "/boot/grub/grub.cfg" - ].each {|c| - cfg = c if FileTest.file? c - } - fail("Cannot find grub.cfg location to use with grub-mkconfig") unless cfg - super - mkconfig "-o", cfg + + require 'puppetx/augeasproviders_grub/util' + PuppetX::AugeasprovidersGrub::Util.grub2_mkconfig(mkconfig) end end diff --git a/lib/puppet/provider/grub_menuentry/grub.rb b/lib/puppet/provider/grub_menuentry/grub.rb index 347c509..8d07e3a 100644 --- a/lib/puppet/provider/grub_menuentry/grub.rb +++ b/lib/puppet/provider/grub_menuentry/grub.rb @@ -79,7 +79,7 @@ def self.get_modules(aug, path) end def self.instances - require 'puppetx/augeasproviders_grub/menuentry' + require 'puppetx/augeasproviders_grub/util' resources = [] @@ -132,7 +132,7 @@ def self.instances def initialize(*args) - require 'puppetx/augeasproviders_grub/menuentry' + require 'puppetx/augeasproviders_grub/util' @grubby_info = {} begin diff --git a/lib/puppet/provider/grub_menuentry/grub2.rb b/lib/puppet/provider/grub_menuentry/grub2.rb index 319bc7b..d90fb09 100644 --- a/lib/puppet/provider/grub_menuentry/grub2.rb +++ b/lib/puppet/provider/grub_menuentry/grub2.rb @@ -3,7 +3,7 @@ # Copyright (c) 2016 Trevor Vaughan # Licensed under the Apache License, Version 2.0 -Puppet::Type.type(:grub_menuentry).provide(:grub2) do +Puppet::Type.type(:grub_menuentry).provide(:grub2, :parent => Puppet::Type.type(:augeasprovider).provider(:default)) do desc "Provides for the manipulation of GRUB2 menuentries" has_feature :grub2 @@ -236,7 +236,7 @@ def self.grub2_menuentries(config, current_default) end def self.instances - require 'puppetx/augeasproviders_grub/menuentry' + require 'puppetx/augeasproviders_grub/util' @grubby_default_index ||= (grubby '--default-index').strip @@ -269,7 +269,7 @@ def self.prefetch(resources) def initialize(*args) super(*args) - require 'puppetx/augeasproviders_grub/menuentry' + require 'puppetx/augeasproviders_grub/util' @grubby_info = {} begin @@ -490,6 +490,10 @@ def initrd=(newval) end def flush + super + + require 'puppetx/augeasproviders_grub/util' + @property_hash[:name] = self.name if @property_hash[:kernel] =~ /(\d.+)/ @@ -536,7 +540,7 @@ def flush FileUtils.rm_f(legacy_target) # Need to rebuild the full grub config if we removed a legacy target - grub2_mkconfig + PuppetX::AugeasprovidersGrub::Util.grub2_mkconfig(mkconfig) end end else @@ -568,7 +572,7 @@ def flush # Need to remove the BLS config if we moved it to be legacy FileUtils.rm_f(bls_target) if File.exist?(bls_target) - grub2_mkconfig + PuppetX::AugeasprovidersGrub::Util.grub2_mkconfig(mkconfig) end end @@ -746,51 +750,4 @@ def construct_grub2cfg_entry(property_hash, header_comment='### PUPPET MANAGED # return output end - - # Run the grub2-mkconfig command on the discovered file paths deconflicting - # across symlinks - def grub2_mkconfig(cfg_paths=[]) - tgt_files = [] - - os_info = Facter.value(:os) - if os_info - os_name = Facter.value(:os)['name'] - else - # Support for old versions of Facter - unless os_name - os_name = Facter.value(:operatingsystem) - end - end - - cfg_paths = [ - "/etc/grub2.cfg", - "/etc/grub2-efi.cfg", - # Handle the standard EFI naming convention - "/boot/efi/EFI/#{os_name.downcase}/grub.cfg", - "/boot/grub2/grub.cfg", - "/boot/grub/grub.cfg" - ] if cfg_paths.empty? - - cfg_paths.each do |path| - begin - tgt_files << File.realpath(path) - rescue - next - end - end - - cfg_paths = cfg_paths.select{|x| FileTest.file?(x)} - - fail("Cannot find a grub configuration at any of '#{cfg_paths.join(', ')}' to use with #{command(:mkconfig)}") if cfg_paths.empty? - - # This takes a while to run - mkconfig_output = mkconfig - - tgt_files.uniq.each do |cfg_path| - File.open(cfg_path, 'w') do |fh| - fh.puts(mkconfig_output) - fh.flush - end - end - end end diff --git a/lib/puppet/provider/grub_user/grub2.rb b/lib/puppet/provider/grub_user/grub2.rb index 000da66..21c192e 100644 --- a/lib/puppet/provider/grub_user/grub2.rb +++ b/lib/puppet/provider/grub_user/grub2.rb @@ -3,7 +3,7 @@ # Copyright (c) 2016 Trevor Vaughan # Licensed under the Apache License, Version 2.0 -Puppet::Type.type(:grub_user).provide(:grub2) do +Puppet::Type.type(:grub_user).provide(:grub2, :parent => Puppet::Type.type(:augeasprovider).provider(:default)) do desc "Provides for the manipulation of GRUB2 User Entries" has_feature :grub2 @@ -21,7 +21,7 @@ def self.mkconfig_path mk_resource_methods def self.grub2_cfg - require 'puppetx/augeasproviders_grub/menuentry' + require 'puppetx/augeasproviders_grub/util' PuppetX::AugeasprovidersGrub::Util.grub2_cfg end @@ -31,7 +31,7 @@ def grub2_cfg end def self.grub2_cfg_path - require 'puppetx/augeasproviders_grub/menuentry' + require 'puppetx/augeasproviders_grub/util' PuppetX::AugeasprovidersGrub::Util.grub2_cfg_path end @@ -223,6 +223,8 @@ def purge end def flush + super + # This is to clean up the legacy file that was put in place incorrectly # prior to the standard 01_users configuration file legacy_file = '/etc/grub.d/01_puppet_managed_users' @@ -275,7 +277,7 @@ def flush # This really shouldn't happen but could if people start adding users in other files. if output == @property_hash[:_target_file_content] err("Please ensure that your *active* GRUB2 configuration is correct. #{self.class} thinks that you need an update, but your file content did not change") - else output == @property_hash[:_target_file_content] + else fh = File.open(resource[:target], 'w') fh.puts(output) fh.flush @@ -284,7 +286,8 @@ def flush FileUtils.chmod(0755, resource[:target]) end - mkconfig "-o", grub2_cfg_path + require 'puppetx/augeasproviders_grub/util' + PuppetX::AugeasprovidersGrub::Util.grub2_mkconfig(mkconfig) end private diff --git a/lib/puppet/provider/kernel_parameter/grub2.rb b/lib/puppet/provider/kernel_parameter/grub2.rb index b95759b..6da1ca4 100644 --- a/lib/puppet/provider/kernel_parameter/grub2.rb +++ b/lib/puppet/provider/kernel_parameter/grub2.rb @@ -154,36 +154,9 @@ def value=(newval) end def flush - os_info = Facter.value(:os) - if os_info - os_name = Facter.value(:os)['name'] - else - # Support for old versions of Facter - unless os_name - os_name = Facter.value(:operatingsystem) - end - end - - cfg = [] - [ - "/etc/grub2-efi.cfg", - # Handle the standard EFI naming convention - "/boot/efi/EFI/#{os_name.downcase}/grub.cfg", - "/boot/grub2/grub.cfg", - "/boot/grub/grub.cfg" - ].each {|c| - if FileTest.file?(c) || ( FileTest.symlink?(c) && - FileTest.directory?(File.dirname(File.absolute_path(File.readlink(c)))) ) - - cfg << c - - end - } - fail("Cannot find grub.cfg location to use with grub-mkconfig") unless cfg - super - cfg.each {|c| - mkconfig "-o", c - } + + require 'puppetx/augeasproviders_grub/util' + PuppetX::AugeasprovidersGrub::Util.grub2_mkconfig(mkconfig) end end diff --git a/lib/puppetx/augeasproviders_grub/menuentry.rb b/lib/puppetx/augeasproviders_grub/util.rb similarity index 74% rename from lib/puppetx/augeasproviders_grub/menuentry.rb rename to lib/puppetx/augeasproviders_grub/util.rb index 8467b95..6aa5156 100644 --- a/lib/puppetx/augeasproviders_grub/menuentry.rb +++ b/lib/puppetx/augeasproviders_grub/util.rb @@ -122,40 +122,59 @@ def self.munge_grubby_value(value, flavor, grubby_info) return value end - # Return the location of the GRUB2 configuration on the system. - # Raise an error if not found. + # Return the name of the current operating system or an empty string if + # not found. # - # @return (String) The full path to the GRUB2 configuration file. - def self.grub2_cfg_path + # @return (String) The current operating system name + def self.os_name + # The usual fact + (Facter.value(:os) && Facter.value(:os)['name']) || + # Legacy support + Facter.value(:operatingsystem) || + # Fallback + '' + end + + # Return the location of all valid GRUB2 configurations on the system. + # + # @raise (Puppet::Error) if no path is found + # + # @return (Array[String]) Paths to all system GRUB2 configuration files. + def self.grub2_cfg_paths paths = [ '/etc/grub2.cfg', - '/boot/grub/grub.cfg', - '/boot/grub2/grub.cfg' + '/etc/grub2-efi.cfg', + "/boot/efi/EFI/#{self.os_name.downcase}/grub.cfg", + '/boot/grub2/grub.cfg', + '/boot/grub/grub.cfg' ] - if File.exist?('/sys/firmware/efi') - os_info = Facter.value(:os) - if os_info - os_name = Facter.value(:os)['name'] - else - # Support for old versions of Facter - unless os_name - os_name = Facter.value(:operatingsystem) - end + valid_paths = paths.map do |path| + begin + real_path = File.realpath(path) + real_path if (File.readable?(real_path) && !File.directory?(real_path)) + rescue Errno::ENOENT + nil end + end.compact.uniq - paths = [ - '/etc/grub2-efi.cfg', - # Handle the standard EFI naming convention - "/boot/efi/EFI/#{os_name.downcase}/grub.cfg" - ] + paths - end + fail(%{No grub configuration found at '#{paths.join("', '")}'}) if valid_paths.empty? - paths.each do |path| - return path if (File.readable?(path) && !File.directory?(path)) - end + valid_paths + end - raise Puppet::Error, 'Could not find a GRUB2 configuration on the system' + # Return the location of the first discovered GRUB2 configuration. + # + # @raise (Puppet::Error) if no path is found + # + # @return (String) The full path to the GRUB2 configuration file. + def self.grub2_cfg_path + + paths = self.grub2_cfg_paths + + raise Puppet::Error, 'Could not find a GRUB2 configuration on the system' if paths.empty? + + paths.first end # Return the contents of the GRUB2 configuration on the system. @@ -166,6 +185,30 @@ def self.grub2_cfg return File.read(grub2_cfg_path) end + # Run grub2-mkconfig on all passed configurations + # + # @param mkconfig_output (String) + # The output of grub2-mkconfig + # + # @param configs (Array[String]) + # The output target paths + # + # @raise (Puppet::Error) if an empty string is passed as the file content + # + # @return (Array[String]) Updated paths + def self.grub2_mkconfig(mkconfig_output, configs = self.grub2_cfg_paths) + fail('No output from grub2-mkconfig') if mkconfig_output.strip.empty? + + configs.each do |config_path| + File.open(config_path, 'w') do |fh| + fh.puts(mkconfig_output) + fh.flush + end + end + + configs + end + # Return a list of options that have the kernel path prepended and are # formatted with all processing arguments handled. # diff --git a/metadata.json b/metadata.json index b987eeb..326a018 100644 --- a/metadata.json +++ b/metadata.json @@ -36,28 +36,31 @@ "operatingsystem": "RedHat", "operatingsystemrelease": [ "6", - "7" + "7", + "8.1" ] }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "6", - "7" + "7", + "8.1" ] }, { "operatingsystem": "OracleLinux", "operatingsystemrelease": [ "6", - "7" + "7", + "8.1" ] } ], "requirements": [ { "name": "puppet", - "version_requirement": ">= 5.0.0 < 7.0.0" + "version_requirement": ">= 5.0.0 < 8.0.0" } ] } diff --git a/spec/acceptance/nodesets/default.yml b/spec/acceptance/nodesets/default.yml index 5e43504..ab7546c 100644 --- a/spec/acceptance/nodesets/default.yml +++ b/spec/acceptance/nodesets/default.yml @@ -14,16 +14,9 @@ HOSTS: box: generic/centos8 hypervisor: vagrant - el6: - roles: - - grub - platform: el-6-x86_64 - box: puppetlabs/centos-6.6-64-nocm - box_url: https://vagrantcloud.com/puppetlabs/boxes/centos-6.6-64-nocm - hypervisor: vagrant - CONFIG: log_level: verbose type: aio vagrant_memsize: 256 + puppet_collection: puppet6 ## vb_gui: true diff --git a/spec/unit/puppet/provider/kernel_parameter/grub2_spec.rb b/spec/unit/puppet/provider/kernel_parameter/grub2_spec.rb index 5964c1c..5e773e9 100755 --- a/spec/unit/puppet/provider/kernel_parameter/grub2_spec.rb +++ b/spec/unit/puppet/provider/kernel_parameter/grub2_spec.rb @@ -41,6 +41,9 @@ FileTest.stubs(:file?).with('/etc/grub2-efi.cfg').returns true FileTest.stubs(:file?).with('/boot/grub2/grub.cfg').returns true FileTest.stubs(:exist?).with('/etc/default/grub').returns true + + require 'puppetx/augeasproviders_grub/util' + PuppetX::AugeasprovidersGrub::Util.stubs(:grub2_cfg_paths).returns([ '/dev/null' ]) end context "with full file" do @@ -70,8 +73,7 @@ describe "when creating entries" do before :each do - provider_class.any_instance.expects(:mkconfig).with("-o", "/boot/grub2/grub.cfg") - provider_class.any_instance.expects(:mkconfig).with("-o", "/etc/grub2-efi.cfg") + provider_class.any_instance.expects(:mkconfig).returns('OK') end it "should create no-value entries" do @@ -215,8 +217,7 @@ end it "should delete entries" do - provider_class.any_instance.expects(:mkconfig).with("-o", "/boot/grub2/grub.cfg") - provider_class.any_instance.expects(:mkconfig).with("-o", "/etc/grub2-efi.cfg") + provider_class.any_instance.expects(:mkconfig).returns('OK') apply!(Puppet::Type.type(:kernel_parameter).new( :name => "divider", @@ -245,8 +246,7 @@ end it "should change existing values" do - provider_class.any_instance.expects(:mkconfig).with("-o", "/boot/grub2/grub.cfg") - provider_class.any_instance.expects(:mkconfig).with("-o", "/etc/grub2-efi.cfg") + provider_class.any_instance.expects(:mkconfig).returns('OK') apply!(Puppet::Type.type(:kernel_parameter).new( :name => "elevator", :ensure => :present, @@ -271,8 +271,7 @@ end it "should add value to entry" do - provider_class.any_instance.expects(:mkconfig).with("-o", "/boot/grub2/grub.cfg") - provider_class.any_instance.expects(:mkconfig).with("-o", "/etc/grub2-efi.cfg") + provider_class.any_instance.expects(:mkconfig).returns('OK') apply!(Puppet::Type.type(:kernel_parameter).new( :name => "quiet", :ensure => :present, @@ -297,8 +296,8 @@ end it "should add and remove entries for multiple values" do - provider_class.any_instance.expects(:mkconfig).with("-o", "/boot/grub2/grub.cfg").times(2) - provider_class.any_instance.expects(:mkconfig).with("-o", "/etc/grub2-efi.cfg").times(2) + # This will run once for each parameter resource + provider_class.any_instance.expects(:mkconfig).returns('OK').twice # Add multiple entries apply!(Puppet::Type.type(:kernel_parameter).new(