diff --git a/service/lib/dinstaller/cmdline_args.rb b/service/lib/dinstaller/cmdline_args.rb new file mode 100644 index 000000000..9c05f7cd8 --- /dev/null +++ b/service/lib/dinstaller/cmdline_args.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +# Copyright (c) [2022] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +module DInstaller + # This class is responsible for reading DInstaller kernel cmdline options + class CmdlineArgs + CMDLINE_PATH = "/proc/cmdline" + CMDLINE_PREFIX = "dinst." + + attr_reader :config_url + attr_reader :args + attr_reader :workdir + + # Constructor + # + # @param workdir [String] root directory to read the configuration from + def initialize(workdir: "/") + @workdir = workdir + end + + # Reads the kernel command line options + def read + options = File.read(File.join(workdir, CMDLINE_PATH)) + @config_url = nil + @args = {} + + options.split.each do |option| + next unless option.start_with?(CMDLINE_PREFIX) + + key, value = option.split("=") + key.gsub!(CMDLINE_PREFIX, "") + # Ommit config_url from Config options + next @config_url = value if key == "config_url" + + if key.include?(".") + section, key = key.split(".") + @args[section] = {} unless @args.keys.include?(section) + @args[section][key] = value + else + @args[key.gsub(CMDLINE_PREFIX, "")] = value + end + end + end + end +end diff --git a/service/lib/dinstaller/config_reader.rb b/service/lib/dinstaller/config_reader.rb index c48b1a78c..80f20c26c 100644 --- a/service/lib/dinstaller/config_reader.rb +++ b/service/lib/dinstaller/config_reader.rb @@ -1,8 +1,28 @@ # frozen_string_literal: true +# Copyright (c) [2022] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + require "yast" require "logger" require "dinstaller/config" +require "dinstaller/cmdline_args" require "transfer/file_from_url" Yast.import "URL" @@ -18,9 +38,7 @@ class ConfigReader # Default DInstaller configuration wich should define all the possible values SYSTEM_PATH = "/etc/d-installer.yaml" GIT_PATH = File.expand_path("#{__dir__}/../../etc/d-installer.yaml") - CMDLINE_PATH = "/proc/cmdline" REMOTE_BOOT_CONFIG = "d-installer_boot.yaml" - CMDLINE_PREFIX = "dinst." PATHS = [ "/usr/lib/d-installer.d", @@ -34,6 +52,7 @@ class ConfigReader # Constructor # # @param logger [Logger] + # @param workdir [String] Root directory to read the configuration from def initialize(logger: nil, workdir: "/") @logger = logger || ::Logger.new($stdout) @workdir = workdir @@ -45,7 +64,12 @@ def initialize(logger: nil, workdir: "/") # # @returm [Array] an array with all the configurations read from the system def configs - @configs ||= config_paths.map { |path| config_from_file(path) }.concat(boot_configs) + return @configs if @configs + + @configs = config_paths.map { |path| config_from_file(path) } + @configs << remote_config if remote_config + @configs << cmdline_config if cmdline_config + @configs end # Return a {Config} oject @@ -81,46 +105,37 @@ def copy_file(location, target) res end - # @return [Hash] Cmdline DInstaller options - def cmdline_opts - options = File.read(File.join(workdir, CMDLINE_PATH)) - - options.split.each_with_object({}) do |option, result| - next unless option.start_with?(CMDLINE_PREFIX) - - key, value = option.split("=") - key.gsub!(CMDLINE_PREFIX, "") - if key.include?(".") - section, key = key.split(".") - result[section] = {} unless result.keys.include?(section) - result[section][key] = value - else - result[key.gsub(CMDLINE_PREFIX, "")] = value - end - end + def cmdline_reader + return @cmdline_reader if @cmdline_reader + + @cmdline_reader = CmdlineArgs.new(workdir: workdir) + @cmdline_reader.read + @cmdline_reader end - # @return [Array] - def boot_configs - options = (cmdline_opts || {}) - return [] if options.empty? + # return [Config] + def cmdline_config + return if cmdline_reader.args.empty? + + Config.new(cmdline_reader.args) + end - result = [Config.new.tap { |c| c.pure_data = options }] - return result if options.fetch("config_url", "").empty? + # return [Config] + def remote_config + return unless cmdline_reader.config_url file_path = File.join(Yast::Directory.tmpdir, REMOTE_BOOT_CONFIG) logger.info "Copying boot config to #{file_path}" - copy_file(options.fetch("config_url"), file_path) - result.prepend(config_from_file(file_path)) - result + copy_file(cmdline_reader.config_url, file_path) + config_from_file(file_path) end # loads correct yaml file def config_from_file(path = nil) raise "Missing config file at #{path}" unless File.exist?(path) - Config.new.tap { |c| c.pure_data = YAML.safe_load(File.read(path)) } + Config.new(YAML.safe_load(File.read(path))) end def default_path diff --git a/service/test/dinstaller/cmdline_args_test.rb b/service/test/dinstaller/cmdline_args_test.rb new file mode 100644 index 000000000..da8b5f8cf --- /dev/null +++ b/service/test/dinstaller/cmdline_args_test.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Copyright (c) [2022] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require_relative "../test_helper" +require "dinstaller/cmdline_args" + +describe DInstaller::CmdlineArgs do + let(:workdir) { File.join(FIXTURES_PATH, "root_dir") } + subject { described_class.new(workdir: workdir) } + + describe "#read" do + it "reads the kernel command line options" do + expect { subject.read }.to change { subject.args }.to({ "web" => { "ssl" => "MODIFIED" } }) + .and change { subject.config_url }.to("http://example.org/d-installer.yaml") + end + end +end diff --git a/service/test/dinstaller/config_reader_test.rb b/service/test/dinstaller/config_reader_test.rb index ff525ab4e..027f060f2 100644 --- a/service/test/dinstaller/config_reader_test.rb +++ b/service/test/dinstaller/config_reader_test.rb @@ -44,7 +44,6 @@ expect(configs.size).to eql(3) expect(configs[0].data.dig("web", "ssl")).to eql(nil) expect(configs[1].data.dig("web", "ssl")).to eql("WHATEVER") - expect(configs[2].data.fetch("config_url")).to eql("http://example.org/dud/dinstaller.yml") expect(configs[2].data.dig("web", "ssl")).to eql("MODIFIED") end end diff --git a/service/test/dinstaller/software_test.rb b/service/test/dinstaller/software_test.rb index c39b45c27..496118d54 100644 --- a/service/test/dinstaller/software_test.rb +++ b/service/test/dinstaller/software_test.rb @@ -38,7 +38,8 @@ let(:gpg_keys) { [] } before do - allow(config).to receive(:data).and_return({ "software" => { "installation_repositories" => [] } }) + allow(config).to receive(:data) + .and_return({ "software" => { "installation_repositories" => [] } }) allow(Yast::Pkg).to receive(:TargetInitialize) allow(Yast::Pkg).to receive(:ImportGPGKey) allow(Dir).to receive(:glob).with(/keys/).and_return(gpg_keys) diff --git a/service/test/fixtures/root_dir/proc/cmdline b/service/test/fixtures/root_dir/proc/cmdline index b4ce900f8..b519906ae 100644 --- a/service/test/fixtures/root_dir/proc/cmdline +++ b/service/test/fixtures/root_dir/proc/cmdline @@ -1 +1 @@ -dinst.config_url=http://example.org/dud/dinstaller.yml dinst.web.ssl=MODIFIED +dinst.config_url=http://example.org/d-installer.yaml dinst.web.ssl=MODIFIED