diff --git a/service/etc/agama.yaml b/service/etc/agama.yaml index 463126c46e..f300d0f273 100644 --- a/service/etc/agama.yaml +++ b/service/etc/agama.yaml @@ -1,2 +1,4 @@ -include: - - "../conf.d/*.yaml" +web: + ssl: null + ssl_cert: null + ssl_key: null diff --git a/service/lib/agama/config.rb b/service/lib/agama/config.rb index f97e11f006..7bd73d8fce 100644 --- a/service/lib/agama/config.rb +++ b/service/lib/agama/config.rb @@ -33,6 +33,7 @@ module Agama class Config # @return [Hash] configuration data attr_accessor :pure_data + attr_accessor :logger class << self attr_accessor :current, :base @@ -96,7 +97,7 @@ def pick_product(product_id) # hash of available base products for current architecture def products return @products if @products - products = ProductReader.new(@logger).load_products + products = ProductReader.new(logger: @logger).load_products products.select! do |product| product["archs"].nil? || @@ -119,7 +120,13 @@ def multi_product? # # @return [Config] def copy - Marshal.load(Marshal.dump(self)) + logger = self.logger + @logger = nil # cannot dump logger as it can contain IO + res = Marshal.load(Marshal.dump(self)) + @logger = logger + res.logger = logger + + res end # Returns a new {Config} with the merge of the given ones diff --git a/service/lib/agama/product_reader.rb b/service/lib/agama/product_reader.rb index d298e636b7..0d94371981 100644 --- a/service/lib/agama/product_reader.rb +++ b/service/lib/agama/product_reader.rb @@ -38,15 +38,13 @@ class ProductReader # Constructor # # @param logger [Logger] - # @param workdir [String] Root directory to read the configuration from - def initialize(logger: nil, workdir: "/") + def initialize(logger: nil) @logger = logger || ::Logger.new($stdout) - @workdir = workdir end def load_products glob = File.join(default_path, "*.{yaml,yml}") - Dir.glob(glob).each_with_object do |path, result| + Dir.glob(glob).each_with_object([]) do |path, result| # support also single product file products = Array(load_file(path)) result.concat(products) diff --git a/service/lib/agama/security.rb b/service/lib/agama/security.rb index e067ca2e7a..1dafd36a03 100644 --- a/service/lib/agama/security.rb +++ b/service/lib/agama/security.rb @@ -73,7 +73,7 @@ def write end def probe - selected_lsm = config.data["security"]["lsm"] + selected_lsm = config.data.dig("security", "lsm") lsm_config.select(selected_lsm) patterns = if selected_lsm.nil? diff --git a/service/lib/agama/software/manager.rb b/service/lib/agama/software/manager.rb index 1abf0d678f..5d12ea712f 100644 --- a/service/lib/agama/software/manager.rb +++ b/service/lib/agama/software/manager.rb @@ -67,7 +67,7 @@ def initialize(config, logger) @logger = logger @languages = DEFAULT_LANGUAGES @products = @config.products - if @config.multi_product? + if @config.multi_product? || @products.empty? @product = nil else @product = @products.keys.first # use the available product as default diff --git a/service/products.d/opensuse.yaml b/service/products.d/opensuse.yaml index bb6e7b38e2..08cf9be7a0 100644 --- a/service/products.d/opensuse.yaml +++ b/service/products.d/opensuse.yaml @@ -1,4 +1,4 @@ -- id: openSUSE-TW +- id: Tumbleweed name: openSUSE Tumbleweed description: 'The Tumbleweed distribution is a pure rolling release version of openSUSE containing the latest "stable" versions of all software @@ -139,7 +139,7 @@ - ext4 - xfs -- id: openSUSE-Leap16 +- id: Leap16 name: openSUSE Leap 16.0 archs: x86_64,aarch64 description: '[Experimental project] openSUSE Leap 16 is built on top of the next generation Adaptable Linux Platform (ALP) from SUSE.' diff --git a/service/run_tests_in_container.sh b/service/run_tests_in_container.sh new file mode 100644 index 0000000000..da0423390d --- /dev/null +++ b/service/run_tests_in_container.sh @@ -0,0 +1,18 @@ +#! /bin/bash + +set -ex +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +podman create -ti --rm --entrypoint '["sh", "-c"]' --name agama_ruby_tests -v $SCRIPT_DIR/..:/checkout registry.opensuse.org/yast/head/containers_tumbleweed/yast-ruby sh +podman start agama_ruby_tests +podman exec agama_ruby_tests zypper --non-interactive install yast2-iscsi-client ruby3.2-rubygem-eventmachine +if podman exec --workdir /checkout/service agama_ruby_tests rake test:unit; then + if [ "$KEEP_RUNNING" != "1" ]; then + podman stop agama_ruby_test + fi + echo "Tests passed" +else + echo "Tests failed" + echo "To get into container use: podman attach agama_ruby_tests" + echo "git checkout is located at /checkout" + echo "To remove container use: podman rm agama_ruby_tests" +fi diff --git a/service/test/agama/config_reader_test.rb b/service/test/agama/config_reader_test.rb index c7e115f77e..ea4ea3f7e8 100644 --- a/service/test/agama/config_reader_test.rb +++ b/service/test/agama/config_reader_test.rb @@ -35,7 +35,7 @@ it "returns a Config object with the configuration read from the given file" do config = subject.config_from_file(File.join(workdir, "etc", "agama.yaml")) expect(config).to be_a(Agama::Config) - expect(config.data["products"].keys).to include("Tumbleweed") + expect(config.data["web"].keys).to include("ssl") end end diff --git a/service/test/agama/config_test.rb b/service/test/agama/config_test.rb index c61714ee9c..140010aed7 100644 --- a/service/test/agama/config_test.rb +++ b/service/test/agama/config_test.rb @@ -26,7 +26,7 @@ let(:config) { described_class.new("web" => { "ssl" => "SOMETHING" }) } before do - allow_any_instance_of(Agama::ConfigReader).to receive(:config).and_return(config) + allow_any_instance_of(Agama::ProductReader).to receive(:load_products).and_return([]) end describe ".load" do @@ -53,12 +53,12 @@ File.join(FIXTURES_PATH, "root_dir", "etc", "agama.yaml") ) expect(config).to be_a(described_class) - expect(config.data["products"].size).to eq(3) end end describe ".reset" do it "resets base and current configuration" do + allow_any_instance_of(Agama::ConfigReader).to receive(:config).and_return(config) described_class.load expect { described_class.reset }.to change { described_class.base }.from(config).to(nil) .and change { described_class.current }.to(nil) @@ -91,17 +91,25 @@ describe "#products" do it "returns products available for current hardware" do - subject = described_class.from_file(File.join(FIXTURES_PATH, "agama-archs.yaml")) - expect(subject.products.size).to eq 2 + allow_any_instance_of(Agama::ProductReader).to receive(:load_products).and_return([ + { + "id" => "test", + "archs" => "x86_64" + }, + { + "id" => "test2", + "archs" => "s390x" + } + ]) + expect(Yast2::ArchFilter).to receive(:from_string).twice.and_return(double(match?: true), double(match?: false)) + expect(subject.products.size).to eq 1 end end describe "#multi_product?" do context "when more than one product is defined" do - subject do - described_class.from_file( - File.join(FIXTURES_PATH, "root_dir", "etc", "agama.yaml") - ) + before do + allow_any_instance_of(Agama::ProductReader).to receive(:load_products).and_call_original end it "returns true" do @@ -110,11 +118,13 @@ end context "when just one product is defined" do - subject do - described_class.from_file(File.join(FIXTURES_PATH, "agama-single.yaml")) + before do + allow_any_instance_of(Agama::ProductReader).to receive(:load_products).and_call_original + products = Agama::ProductReader.new.load_products + allow_any_instance_of(Agama::ProductReader).to receive(:load_products).and_return([products.first]) end - it "returns true" do + it "returns false" do expect(subject.multi_product?).to eq(false) end end diff --git a/service/test/agama/dbus/server_manager_test.rb b/service/test/agama/dbus/server_manager_test.rb index 6fe836c83d..58e0af96c1 100644 --- a/service/test/agama/dbus/server_manager_test.rb +++ b/service/test/agama/dbus/server_manager_test.rb @@ -65,7 +65,7 @@ describe "#start_server" do it "starts the dbus-daemon and returns the PID" do expect(Process).to receive(:spawn) - .with(/dbus-daemon/, "--config-file", /dbus.conf/, any_args) + .with(/dbus-daemon/, "--config-file", any_args) # config file loc depends on pwd .and_return(1000) expect(Process).to receive(:detach).with(1000) expect(subject.start_server).to eq(1000) diff --git a/service/test/agama/software/manager_test.rb b/service/test/agama/software/manager_test.rb index 1dd557a6f1..3d9294d5bb 100644 --- a/service/test/agama/software/manager_test.rb +++ b/service/test/agama/software/manager_test.rb @@ -70,6 +70,8 @@ before do allow(Yast::Pkg).to receive(:TargetInitialize) allow(Yast::Pkg).to receive(:ImportGPGKey) + # allow glob to work for other calls + allow(Dir).to receive(:glob).and_call_original allow(Dir).to receive(:glob).with(/keys/).and_return(gpg_keys) allow(Yast::Packages).to receive(:Proposal).and_return({}) allow(Yast::InstURL).to receive(:installInf2Url).with("") @@ -79,6 +81,7 @@ allow(Agama::DBus::Clients::Questions).to receive(:new).and_return(questions_client) allow(Agama::Software::RepositoriesManager).to receive(:new).and_return(repositories) allow(Agama::Software::Proposal).to receive(:new).and_return(proposal) + allow_any_instance_of(Agama::ProductReader).to receive(:load_products).and_call_original end describe "#probe" do @@ -116,7 +119,7 @@ end it "registers the repository from config" do - expect(repositories).to receive(:add).with(/tumbleweed/) + expect(repositories).to receive(:add).with(/Dolomite/) expect(repositories).to receive(:load) subject.probe end @@ -126,9 +129,8 @@ it "returns the list of known products" do products = subject.products expect(products.size).to eq(3) - id, data = products.first - expect(id).to eq("Tumbleweed") - expect(data).to include( + expect(products["Tumbleweed"]).to_not eq nil + expect(products["Tumbleweed"]).to include( "name" => "openSUSE Tumbleweed", "description" => String ) @@ -152,16 +154,11 @@ expect(proposal).to receive(:set_resolvables) .with("agama", :pattern, ["enhanced_base"]) expect(proposal).to receive(:set_resolvables) - .with("agama", :pattern, ["optional_base"], optional: true) + .with("agama", :pattern, [], {optional: true}) expect(proposal).to receive(:set_resolvables) - .with("agama", :package, ["mandatory_pkg"]) + .with("agama", :package, ["NetworkManager"]) expect(proposal).to receive(:set_resolvables) - .with("agama", :package, ["optional_pkg"], optional: true) - subject.propose - - expect(Yast::Arch).to receive(:s390).and_return(true) - expect(proposal).to receive(:set_resolvables) - .with("agama", :package, ["mandatory_pkg", "mandatory_pkg_s390"]) + .with("agama", :package, [], {optional: true}) subject.propose end end diff --git a/service/test/fixtures/root_dir/etc/agama.yaml b/service/test/fixtures/root_dir/etc/agama.yaml index c87e4013ad..5ae38001f0 100644 --- a/service/test/fixtures/root_dir/etc/agama.yaml +++ b/service/test/fixtures/root_dir/etc/agama.yaml @@ -1,296 +1,17 @@ -products: - Tumbleweed: - name: openSUSE Tumbleweed - description: 'The Tumbleweed distribution is a pure rolling release version - of openSUSE containing the latest "stable" versions of all software - instead of relying on rigid periodic release cycles. The project does - this for users that want the newest stable software.' - Leap Micro: - name: openSUSE Leap Micro 5.2 - description: 'Leap Micro is an ultra-reliable, lightweight operating system - built for containerized and virtualized workloads. This community version - is based on SUSE Linux Enterprise Micro, which leverages the enterprise - hardened security and compliance components of SUSE Linux Enterprise.' - Leap: - name: openSUSE Leap 15.4 - description: 'Leap uses source from SUSE Linux Enterprise (SLE), which - gives Leap a level of stability unmatched by other Linux distributions, - and combines that with community developments to give users, developers - and sysadmins the best stable Linux experience available.' - web: ssl: null ssl_cert: null ssl_key: null - -Tumbleweed: - software: - installation_repositories: - - https://download.opensuse.org/tumbleweed/repo/oss/ - - https://download.opensuse.org/tumbleweed/repo/non-oss/ - - https://download.opensuse.org/update/tumbleweed/ - mandatory_patterns: - - enhanced_base # only pattern that is shared among all roles on TW - optional_patterns: - - optional_base - mandatory_packages: - - package: mandatory_pkg - - package: mandatory_pkg_s390 - archs: s390 - optional_packages: - - optional_pkg - base_product: openSUSE - - security: - lsm: apparmor - available_lsms: - apparmor: - patterns: - - apparmor - selinux: - patterns: - - selinux - policy: permissive - none: - patterns: null - - storage: - volumes: - - "/" - - "swap" - volume_templates: - - mount_path: "/" - filesystem: btrfs - btrfs: - snapshots: true - read_only_root: true - default_subvolume: "@" - subvolumes: - - path: home - - path: opt - - path: root - - path: srv - - path: usr/local - # Unified var subvolume - https://lists.opensuse.org/opensuse-packaging/2017-11/msg00017.html - - path: var - copy_on_write: false - - # Architecture specific subvolumes - - path: boot/grub2/arm64-efi - archs: aarch64 - - path: boot/grub2/arm-efi - archs: arm - - path: boot/grub2/i386-pc - archs: x86_64 - - path: boot/grub2/powerpc-ieee1275 - archs: ppc,!board_powernv - - path: boot/grub2/s390x-emu - archs: s390 - - path: boot/grub2/x86_64-efi - archs: x86_64 - - path: boot/grub2/riscv64-efi - archs: riscv64 - - size: - auto: true - outline: - required: true - auto_size: - base_min: 5 GiB - base_max: 20 GiB - snapshots_increment: 10 GiB - min_fallback_for: - - "/home" - - "/home" - snapshots_configurable: true - - - mount_path: "/home" - filesystem: xfs - size: - auto: false - min: 10 GiB - max: unlimited - outline: - required: false - - - mount_path: "swap" - filesystem: swap - size: - auto: false - min: 1 GiB - max: 2 GiB - outline: - required: false - -Leap: - software: - installation_repositories: - # TODO: support somehow $releasever in URL - - https://download.opensuse.org/distribution/leap/15.4/repo/oss/ - - https://download.opensuse.org/distribution/leap/15.4/repo/non-oss/ - - https://download.opensuse.org/update/leap/15.4/oss/ - - https://download.opensuse.org/update/leap/15.4/non-oss/ - - https://download.opensuse.org/update/leap/15.4/sle/ - - https://download.opensuse.org/update/leap/15.4/backports/ - mandatory_patterns: - - enhanced_base # For now lets pick some minimal one - optional_patterns: null # no optional pattern shared - base_product: Leap - - security: - # TODO: check if skelcd for Leap 15.4 is correct as code is using lsm in globals, but skelcd contain selinux only - lsm: apparmor - available_lsms: - apparmor: - patterns: - - apparmor - selinux: - patterns: - - selinux - policy: disabled - none: - patterns: null - - storage: - volumes: - - "/" - - "swap" - volume_templates: - - mount_path: "/" - filesystem: btrfs - btrfs: - snapshots: true - read_only_root: true - default_subvolume: "@" - subvolumes: - - path: home - - path: opt - - path: root - - path: srv - - path: usr/local - # Unified var subvolume - https://lists.opensuse.org/opensuse-packaging/2017-11/msg00017.html - - path: var - copy_on_write: false - - # Architecture specific subvolumes - - path: boot/grub2/arm64-efi - archs: aarch64 - - path: boot/grub2/arm-efi - archs: arm - - path: boot/grub2/i386-pc - archs: x86_64 - - path: boot/grub2/powerpc-ieee1275 - archs: ppc,!board_powernv - - path: boot/grub2/s390x-emu - archs: s390 - - path: boot/grub2/x86_64-efi - archs: x86_64 - - path: boot/grub2/riscv64-efi - archs: riscv64 - - size: - auto: true - outline: - required: true - auto_size: - base_min: 5 GiB - base_max: 20 GiB - snapshots_increment: 10 GiB - min_fallback_for: - - "/home" - - "/home" - snapshots_configurable: true - - - mount_path: "/home" - filesystem: xfs - size: - auto: false - min: 10 GiB - max: unlimited - outline: - required: false - - - mount_path: "swap" - filesystem: swap - size: - auto: false - min: 1 GiB - max: 2 GiB - outline: - required: false - -Leap Micro: - software: - installation_repositories: - - https://download.opensuse.org/distribution/leap-micro/5.2/product/repo/Leap-Micro-5.2-x86_64-Media/ - mandatory_patterns: - - microos-base - - microos-hardware - - microos-bootloader - - microos-defaults - - microos-basesystem - optional_patterns: null # no optional pattern shared - base_product: Leap-Micro - - security: - lsm: selinux - available_lsms: - selinux: - patterns: - - microos-selinux - policy: enforcing - none: - patterns: null - - storage: - volumes: - - "/" - - "/var" - volume_templates: - - mount_path: "/" - filesystem: btrfs - btrfs: - snapshots: true - read_only_root: true - default_subvolume: "@" - subvolumes: - - path: root - - path: home - - path: opt - - path: srv - - path: root - - path: boot/writable - - path: usr/local - - path: boot/grub2/arm64-efi - archs: aarch64 - - path: boot/grub2/i386-pc - archs: x86_64 - - path: boot/grub2/powerpc-ieee1275 - archs: ppc,!board_powernv - - path: boot/grub2/s390x-emu - archs: s390 - - path: boot/grub2/x86_64-efi - archs: x86_64 - - size: - auto: true - outline: - required: true - auto_size: - base_min: 5 GiB - base_max: 20 GiB - snapshots_increment: 10 GiB - min_fallback_for: - - "/var" - - "/var" - snapshots_configurable: false - - - mount_path: "/var" - filesystem: btrfs - size: - auto: false - min: 5 GiB - max: unlimited - outline: - required: false +security: + lsm: apparmor + available_lsms: + apparmor: + patterns: + - apparmor + selinux: + patterns: + - selinux + policy: permissive + none: + patterns: null diff --git a/service/test/test_helper.rb b/service/test/test_helper.rb index ff1f933d46..1b611f9acd 100644 --- a/service/test/test_helper.rb +++ b/service/test/test_helper.rb @@ -26,6 +26,8 @@ FIXTURES_PATH = File.expand_path("fixtures", __dir__) $LOAD_PATH.unshift(SRC_PATH) +require "agama/product_reader" # to globally mock reading real products + # make sure we run the tests in English locale # (some tests check the output which is marked for translation) ENV["LC_ALL"] = "en_US.UTF-8" @@ -42,6 +44,12 @@ def require(path) end end +RSpec.configure do |c| + c.before do + allow_any_instance_of(Agama::ProductReader).to receive(:load_products).and_return([]) + end +end + if ENV["COVERAGE"] require "simplecov" SimpleCov.start do