diff --git a/library/system/Makefile.am b/library/system/Makefile.am index 4765550da..c4f6ba868 100644 --- a/library/system/Makefile.am +++ b/library/system/Makefile.am @@ -1,3 +1,3 @@ # Makefile.am for yast2/library/system -SUBDIRS = doc src testsuite +SUBDIRS = doc src testsuite test diff --git a/library/system/src/modules/Kernel.rb b/library/system/src/modules/Kernel.rb index 6b3a1470c..ad3fb2922 100644 --- a/library/system/src/modules/Kernel.rb +++ b/library/system/src/modules/Kernel.rb @@ -38,6 +38,16 @@ module Yast class KernelClass < Module + + # default configuration file for Kernel modules loaded on boot + MODULES_CONF_FILE = "yast.conf" + + # directory where configuration for Kernel modules loaded on boot is stored + MODULES_DIR = "/etc/modules-load.d/" + + # SCR path for reading/writing Kernel modules + MODULES_SCR = path(".kernel_modules_to_load") + def main Yast.import "Pkg" @@ -80,13 +90,9 @@ def main # modules loaded on boot - # List of changes in /etc/sysconfig/kernel:MODULES_LOADED_ON_BOOT - # Needs to be stored as a list of changes due to the fact that some RPMs - # change the variable during installation - # list member is a map with keys "operation" (value "add" or "detete") and - # "name" (name of the module) - @kernel_modules_to_load = [] - + # Kernel modules configured to be loaded on boot + @modules_to_load = nil + @modules_to_load_old = nil # kernel was reinstalled @@ -547,74 +553,78 @@ def ComputePackages # functions related to kernel's modules loaded on boot + + + # Resets the internal cache + def reset_modules_to_load + @modules_to_load = nil + end + + # Returns hash of kernel modules to be loaded on boot + # - key is the config file + # - value is list of modules in that particular file + # + # @return [Hash] of modules + def modules_to_load + read_modules_to_load if @modules_to_load.nil? + + @modules_to_load + end + + # Returns whether the given kernel module is included in list of modules + # to be loaded on boot + # + # @param [String] kernel module + # @return [Boolean] whether the given module is in the list + def module_to_be_loaded?(kernel_module) + modules_to_load.values.any? {|m| m.include?(kernel_module)} + end + # Add a kernel module to the list of modules to load after boot # @param string module name - # add the module name to sysconfig variable def AddModuleToLoad(name) Builtins.y2milestone("Adding module to be loaded at boot: %1", name) - @kernel_modules_to_load = Builtins.add( - @kernel_modules_to_load, - { "operation" => "add", "name" => name } - ) - nil + unless module_to_be_loaded?(name) + @modules_to_load[MODULES_CONF_FILE] << name + end end # Remove a kernel module from the list of modules to load after boot # @param [String] name string the name of the module def RemoveModuleToLoad(name) - Builtins.y2milestone("Removing module to be loaded at boot: %1", name) - @kernel_modules_to_load = Builtins.add( - @kernel_modules_to_load, - { "operation" => "remove", "name" => name } - ) + modules_to_load - nil + return true unless module_to_be_loaded?(name) + + Builtins.y2milestone("Removing module to be loaded at boot: %1", name) + @modules_to_load.each do |key, val| + val.delete(name) + end end # SaveModuleToLoad () - # save the sysconfig variable to the file + # save the sysconfig variable to /etc/modules-load.d/*.conf configuration files # @return [Boolean] true on success def SaveModulesToLoad - # if nothing changed, just return success - return true if Builtins.size(@kernel_modules_to_load) == 0 + modules_to_load + success = true - # first read current status - modules_to_load_str = Convert.to_string( - SCR.Read(path(".sysconfig.kernel.MODULES_LOADED_ON_BOOT")) - ) - modules_to_load_str = "" if modules_to_load_str == nil - modules_to_load = Builtins.splitstring(modules_to_load_str, " ") - modules_to_load = Builtins.filter(modules_to_load) { |s| s != "" } - Builtins.y2milestone( - "Read modules to be loaded at boot: %1", - modules_to_load - ) + @modules_to_load.each do |file, modules| + # The content hasn't changed + next if (modules.sort == @modules_to_load_old[file].sort) - # apply operations on the list - Builtins.foreach(@kernel_modules_to_load) do |op_desc| - op = Ops.get(op_desc, "operation", "") - name = Ops.get(op_desc, "name", "") - if op == "remove" - modules_to_load = Builtins.filter(modules_to_load) { |m| m != name } - elsif op == "add" - if !Builtins.contains(modules_to_load, name) - modules_to_load = Builtins.add(modules_to_load, name) - end + if !register_modules_agent(file) + Builtins.y2error("Cannot register new SCR agent for #{file_path} file") + success = false + next end + + SCR::Write(MODULES_SCR, modules) + SCR.UnregisterAgent(MODULES_SCR) end - # and sabe the list - Builtins.y2milestone( - "Saving modules to be loaded at boot: %1", - modules_to_load - ) - modules_to_load_str = Builtins.mergestring(modules_to_load, " ") - SCR.Write( - path(".sysconfig.kernel.MODULES_LOADED_ON_BOOT"), - modules_to_load_str - ) - SCR.Write(path(".sysconfig.kernel"), nil) + success end # kernel was reinstalled stuff @@ -640,6 +650,65 @@ def InformAboutKernelChange @inform_about_kernel_change end + private + + # Registers new SCR agent for a file given as parameter + # + # @param [String] file name in directory defined in MODULES_DIR + def register_modules_agent(file_name) + full_path = File.join(MODULES_DIR, file_name) + + SCR::RegisterAgent( + MODULES_SCR, + term( + :ag_anyagent, + term( + :Description, + + term( + :File, + full_path + ), + + # Comments + "#\n", + + # Read-only? + false, + + term( + :List, + term(:String, "^\n"), + "\n" + ) + ) + ) + ) + end + + # Loads the current configuration of Kernel modules + # to be loaded on boot to the internal cache + # + # @return [Hash] with the configuration + def read_modules_to_load + @modules_to_load = {MODULES_CONF_FILE => []} + + SCR::Read(path(".target.dir"), MODULES_DIR).each do |file_name| + next unless file_name =~ /^.+\.conf$/ + + if !register_modules_agent(file_name) + Builtins.y2error("Cannot register new SCR agent for #{file_path} file") + next + end + + @modules_to_load[file_name] = SCR::Read(MODULES_SCR) + SCR.UnregisterAgent(MODULES_SCR) + end + + @modules_to_load_old = deep_copy(@modules_to_load) + @modules_to_load + end + publish :function => :AddCmdLine, :type => "void (string, string)" publish :function => :GetVgaType, :type => "string ()" publish :function => :SetVgaType, :type => "void (string)" @@ -654,12 +723,16 @@ def InformAboutKernelChange publish :function => :GetFinalKernel, :type => "string ()" publish :function => :ComputePackagesForBase, :type => "list (string, boolean)" publish :function => :ComputePackages, :type => "list ()" - publish :function => :AddModuleToLoad, :type => "void (string)" - publish :function => :RemoveModuleToLoad, :type => "void (string)" - publish :function => :SaveModulesToLoad, :type => "boolean ()" publish :function => :SetInformAboutKernelChange, :type => "void (boolean)" publish :function => :GetInformAboutKernelChange, :type => "boolean ()" publish :function => :InformAboutKernelChange, :type => "boolean ()" + + # Handling for Kernel modules loaded on boot + publish :function => :AddModuleToLoad, :type => "void (string)" + publish :function => :RemoveModuleToLoad, :type => "void (string)" + publish :function => :SaveModulesToLoad, :type => "boolean ()" + publish :function => :reset_modules_to_load, :type => "void ()" + publish :function => :modules_to_load, :type => "map ()" end Kernel = KernelClass.new diff --git a/library/system/test/Makefile.am b/library/system/test/Makefile.am new file mode 100644 index 000000000..1f90e68c4 --- /dev/null +++ b/library/system/test/Makefile.am @@ -0,0 +1,7 @@ +TESTS = \ + kernel_test.rb + +TEST_EXTENSIONS = .rb +RB_LOG_COMPILER = rspec +VERBOSE = 1 +EXTRA_DIST = $(TESTS) diff --git a/library/system/test/data/modules.d/MODULES_LOADED_ON_BOOT.conf b/library/system/test/data/modules.d/MODULES_LOADED_ON_BOOT.conf new file mode 100644 index 000000000..eb21ea55a --- /dev/null +++ b/library/system/test/data/modules.d/MODULES_LOADED_ON_BOOT.conf @@ -0,0 +1,10 @@ +# +# These kernel modules will be loaded on boot +# One module per line +# + +# Some comment +module-a + +# Another comment +module-b diff --git a/library/system/test/data/modules.d/not_a_conf_file b/library/system/test/data/modules.d/not_a_conf_file new file mode 100644 index 000000000..8b6e0c83c --- /dev/null +++ b/library/system/test/data/modules.d/not_a_conf_file @@ -0,0 +1,4 @@ +Whatever is here +must not be loaded +as a kernel +module diff --git a/library/system/test/data/modules.d/user-added-1.conf b/library/system/test/data/modules.d/user-added-1.conf new file mode 100644 index 000000000..ccdc40197 --- /dev/null +++ b/library/system/test/data/modules.d/user-added-1.conf @@ -0,0 +1,7 @@ +user-module-1 +user-module-2 + +# User comment +# on several +# lines +user-module-3 diff --git a/library/system/test/data/modules.d/user-added-2.conf b/library/system/test/data/modules.d/user-added-2.conf new file mode 100644 index 000000000..cbc65c10f --- /dev/null +++ b/library/system/test/data/modules.d/user-added-2.conf @@ -0,0 +1 @@ +user-module-4 diff --git a/library/system/test/kernel_test.rb b/library/system/test/kernel_test.rb new file mode 100755 index 000000000..742621388 --- /dev/null +++ b/library/system/test/kernel_test.rb @@ -0,0 +1,116 @@ +#! /usr/bin/env rspec + +ENV["Y2DIR"] = File.expand_path("../../src", __FILE__) + +require "yast" +require "tmpdir" + +include Yast + +Yast.import "Kernel" + +DEFAULT_DATA_DIR = File.join(File.expand_path(File.dirname(__FILE__)), "data/modules.d") + +describe "Kernel" do + before (:each) do + stub_const("Yast::KernelClass::MODULES_DIR", DEFAULT_DATA_DIR) + @default_modules = { + Yast::KernelClass::MODULES_CONF_FILE => [], + "MODULES_LOADED_ON_BOOT.conf"=>["module-a", "module-b"], + "user-added-1.conf" => ["user-module-1", "user-module-2", "user-module-3"], + "user-added-2.conf"=>["user-module-4"], + } + Yast::Kernel.reset_modules_to_load + end + + describe "#modules_to_load" do + it "returns hash of modules to load" do + expect(Yast::Kernel.modules_to_load).to eq(@default_modules) + end + end + + describe "#module_to_be_loaded?" do + it "tests whether module is loaded on boot" do + ["module-a", "module-b", "user-module-1", "user-module-2", "user-module-3", "user-module-4"].each do |kernel_module| + expect(Yast::Kernel.module_to_be_loaded?(kernel_module)).to be_true + end + + ["module-c", "user-module-5"].each do |kernel_module| + expect(Yast::Kernel.module_to_be_loaded?(kernel_module)).to be_false + end + end + end + + describe "#AddModuleToLoad" do + it "adds new module to be loaded on boot" do + new_module = "new-kernel-module" + expect(Yast::Kernel.module_to_be_loaded?(new_module)).to be_false + Yast::Kernel.AddModuleToLoad new_module + expect(Yast::Kernel.module_to_be_loaded?(new_module)).to be_true + end + + it "adds module only once" do + new_module = "new-kernel-module" + Yast::Kernel.AddModuleToLoad new_module + Yast::Kernel.AddModuleToLoad new_module + expect(Yast::Kernel.modules_to_load.values.flatten.select{|m| m == new_module}.size).to eq(1) + end + end + + describe "#RemoveModuleToLoad" do + it "removes module from list of modules to be loaded on boot" do + module_to_remove = "user-module-2" + expect(Yast::Kernel.module_to_be_loaded?(module_to_remove)).to be_true + Yast::Kernel.RemoveModuleToLoad module_to_remove + expect(Yast::Kernel.module_to_be_loaded?(module_to_remove)).to be_false + end + + it "does not remove module which is not in list" do + module_to_remove = "not-in-list" + expect(Yast::Kernel.module_to_be_loaded?(module_to_remove)).to be_false + Yast::Kernel.RemoveModuleToLoad module_to_remove + expect(Yast::Kernel.module_to_be_loaded?(module_to_remove)).to be_false + end + end + + describe "#SaveModulesToLoad" do + it "stores all modules to be loaded to configuration files" do + Dir.mktmpdir do |tmpdir| + FileUtils.cp_r(DEFAULT_DATA_DIR + "/.", tmpdir) + + stub_const("Yast::KernelClass::MODULES_DIR", tmpdir) + Yast::Kernel.reset_modules_to_load + + # Tests on the default data + ["module-a", "module-b", "user-module-1", "user-module-2", "user-module-3", "user-module-4"].each do |kernel_module| + expect(Yast::Kernel.module_to_be_loaded?(kernel_module)).to be_true + end + + new_module = "new-kernel-module" + remove_module = "user-module-2" + + # Modifying data + Yast::Kernel.AddModuleToLoad new_module + Yast::Kernel.RemoveModuleToLoad remove_module + + expect(Yast::Kernel.SaveModulesToLoad).to be_true + + # Tests on the stored modified data + Yast::Kernel.reset_modules_to_load + ["module-a", "module-b", "user-module-1", "user-module-3", "user-module-4", new_module].each do |kernel_module| + expect(Yast::Kernel.module_to_be_loaded?(kernel_module)).to be_true + end + + expect(Yast::Kernel.module_to_be_loaded?(remove_module)).to be_false + + # Tests directly on the system + number_of_nkm = `grep --count --no-filename #{new_module} #{tmpdir}/*` + expect(number_of_nkm.split.map(&:to_i).inject(:+)).to eq(1) + + number_of_rkm = `grep --count --no-filename #{remove_module} #{tmpdir}/*` + expect(number_of_rkm.split.map(&:to_i).inject(:+)).to eq(0) + end + end + end + +end diff --git a/library/system/testsuite/tests/kernel.out b/library/system/testsuite/tests/kernel.out index 2665b0a73..62d9a1689 100644 --- a/library/system/testsuite/tests/kernel.out +++ b/library/system/testsuite/tests/kernel.out @@ -1,11 +1,4 @@ Dump ---------------------------------------- -Dump Testing modules to load on boot behavior -Return nil -Return nil -Read .sysconfig.kernel.MODULES_LOADED_ON_BOOT "reiserfs xfs" -Write .sysconfig.kernel.MODULES_LOADED_ON_BOOT "xfs ext2" true -Write .sysconfig.kernel nil true -Return true Return nil Return Return ABC=213 DEF=324 diff --git a/library/system/testsuite/tests/kernel.rb b/library/system/testsuite/tests/kernel.rb index 9cc384d92..3bbccf2eb 100644 --- a/library/system/testsuite/tests/kernel.rb +++ b/library/system/testsuite/tests/kernel.rb @@ -78,14 +78,7 @@ def main # test behavior of modules loaded on boot DUMP("----------------------------------------") - DUMP("Testing modules to load on boot behavior") - TEST(lambda { Kernel.AddModuleToLoad("ext2") }, [@READ, @WRITE, @EXEC], 0) - TEST(lambda { Kernel.RemoveModuleToLoad("reiserfs") }, [ - @READ, - @WRITE, - @EXEC - ], 0) - TEST(lambda { Kernel.SaveModulesToLoad }, [@READ, @WRITE, @EXEC], 0) + TEST(lambda { Kernel.HidePasswords(nil) }, [@READ, @WRITE, @EXEC], 0) TEST(lambda { Kernel.HidePasswords("") }, [@READ, @WRITE, @EXEC], 0) diff --git a/package/yast2.changes b/package/yast2.changes index ca61e2f24..a0aed46d1 100644 --- a/package/yast2.changes +++ b/package/yast2.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Thu Oct 31 21:50:05 CET 2013 - locilka@suse.com + +- Configuration of Kernel modules loaded on boot has been moved + to /etc/modules-load.d/*.conf files. Adapted Kernel library + internal handling (bnc#838185). +- 3.1.2 + ------------------------------------------------------------------- Tue Oct 22 11:17:25 UTC 2013 - mfilka@suse.com diff --git a/package/yast2.spec b/package/yast2.spec index 45ba2600a..c3d97a0f6 100644 --- a/package/yast2.spec +++ b/package/yast2.spec @@ -17,7 +17,7 @@ Name: yast2 -Version: 3.1.1 +Version: 3.1.2 Release: 0 BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -33,7 +33,7 @@ BuildRequires: yast2-devtools >= 3.0.6 BuildRequires: yast2-core >= 2.18.12 yast2-pkg-bindings >= 2.20.3 yast2-ycp-ui-bindings >= 2.18.4 # Needed for tests -BuildRequires: rubygem-rspec +BuildRequires: rubygem-rspec grep # for symlinking yardoc duplicates BuildRequires: fdupes