Skip to content

Commit

Permalink
Added class for reading kernel cmdline options
Browse files Browse the repository at this point in the history
  • Loading branch information
teclator committed May 12, 2022
1 parent 9e30b14 commit 4c6f0be
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 33 deletions.
63 changes: 63 additions & 0 deletions 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
75 changes: 45 additions & 30 deletions 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"
Expand All @@ -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",
Expand All @@ -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
Expand All @@ -45,7 +64,12 @@ def initialize(logger: nil, workdir: "/")
#
# @returm [Array<Config>] 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
Expand Down Expand Up @@ -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<Config>]
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
Expand Down
35 changes: 35 additions & 0 deletions 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
1 change: 0 additions & 1 deletion service/test/dinstaller/config_reader_test.rb
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion service/test/dinstaller/software_test.rb
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion 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

0 comments on commit 4c6f0be

Please sign in to comment.