Skip to content

Commit

Permalink
Package availability (#1004)
Browse files Browse the repository at this point in the history
## Problem

The call to the sotware service to check for the availability of a
package is mocked and always returns true, assuming the package is
always available. Of course, the availability of a package depends of
the currently selected product.

## Solution

Perform a D-Bus call to the software service in order to know if a
package is available.

Note: This change exposes a problem in our services. Asking for the
product availability should be done once the software proposal is done,
otherwise the result is not reliable at all, see
#1005. For example, the TPM
option in the storage settings could not appear until the software
service has finished, see #995.

## Testing

* Added new unit tests
* Tested manually
  • Loading branch information
joseivanlopez authored Jan 19, 2024
2 parents ee1bae7 + f827b72 commit d516f74
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 28 deletions.
4 changes: 4 additions & 0 deletions doc/dbus/bus/org.opensuse.Agama.Software1.bus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
<arg name="Name" direction="in" type="s"/>
<arg name="Result" direction="out" type="b"/>
</method>
<method name="IsPackageAvailable">
<arg name="name" direction="in" type="s"/>
<arg name="result" direction="out" type="b"/>
</method>
<method name="UsedDiskSpace">
<arg name="SpaceSize" direction="out" type="s"/>
</method>
Expand Down
10 changes: 10 additions & 0 deletions doc/dbus/org.opensuse.Agama.Software1.doc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@
<arg name="Name" direction="in" type="s"/>
<arg name="Result" direction="out" type="b"/>
</method>
<!--
Whether a package is available for installation.
-->
<method name="IsPackageAvailable">
<!--
Name of the package.
-->
<arg name="name" direction="in" type="s"/>
<arg name="result" direction="out" type="b"/>
</method>
<method name="UsedDiskSpace">
<arg name="SpaceSize" direction="out" type="s"/>
</method>
Expand Down
15 changes: 12 additions & 3 deletions service/lib/agama/dbus/clients/software.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) [2022-2023] SUSE LLC
# Copyright (c) [2022-2024] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -114,13 +114,22 @@ def provisions_selected?(tags)
dbus_object.ProvisionsSelected(tags)
end

# Determines whether a package with the given name is installed
# Determines whether a package is installed.
#
# @param name [String] Package name
# @param name [String] Package name.
# @return [Boolean]
def package_installed?(name)
dbus_object.IsPackageInstalled(name)
end

# Determines whether a package is available.
#
# @param name [String] Package name.
# @return [Boolean]
def package_available?(name)
dbus_object.IsPackageAvailable(name)
end

# Add the given list of resolvables to the packages proposal
#
# @param unique_id [String] Unique identifier for the resolvables list
Expand Down
6 changes: 5 additions & 1 deletion service/lib/agama/dbus/software/manager.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) [2022-2023] SUSE LLC
# Copyright (c) [2022-2024] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -99,6 +99,10 @@ def issues
backend.package_installed?(name)
end

dbus_method :IsPackageAvailable, "in name:s, out result:b" do |name|
backend.package_available?(name)
end

dbus_method(:UsedDiskSpace, "out SpaceSize:s") { backend.used_disk_space }

dbus_method(:Probe) { probe }
Expand Down
29 changes: 28 additions & 1 deletion service/lib/agama/dbus/y2dir/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
Override directory to redirect some yast modules to use D-Bus methods. It is just temporary workaround for POC.
This directory contains some redefinitions of YaST modules in order to call to D-Bus methods instead
of executing the actual code of the module.

# Why is this needed?

Agama relies on YaST code and YaST usually works as a single process. By contrast, Agama works as a
set of different processes (software service, storage service, etc), and each service runs its own
YaST instance.

Having different YaST instances implies that the information is scattered in different processes.
For example, only the YaST instance in the software service has the information about the software
configuration. This means that other YaST instances need to ask to the software YaST instance for
the information.

# How to communicate among YaST instances

A YaST instance can get information from other instance by doing a D-Bus call to the service running
such an instance. For example, the YaST instance in the storage service has to call to the D-Bus API
of the software service instead of directly calling to the software module code. To achieve that,
the storage service replaces the implementation of the YaST software module by its own
implementation which uses D-Bus calls.

# How to replace a YaST module

The code replacement of the YaST modules is done by means of the *Y2DIR* mechanism of YaST. When a
service is started (check *agamactl* script), the YaST modules redefined by the service (under
*lib/agama/dbus/y2dir/*) are added to the *Y2DIR* environment variable. YaST takes precedence of the
paths at *Y2DIR*, so these files will be loaded instead of the files originally delivered by YaST.
35 changes: 17 additions & 18 deletions service/lib/agama/dbus/y2dir/manager/modules/Package.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) [2022] SUSE LLC
# Copyright (c) [2022-2024] SUSE LLC
#
# All Rights Reserved.
#
Expand All @@ -22,36 +22,35 @@

# :nodoc:
module Yast
# Replacement for the Yast::Package module
#
# @see https://github.com/yast/yast-yast2/blob/b8cd178b7f341f6e3438782cb703f4a3ab0529ed/library/packages/src/modules/Package.rb
# Replacement for the Yast::Package module.
class PackageClass < Module
def main
puts "Loading mocked module #{__FILE__}"
@client = Agama::DBus::Clients::Software.new
end

# Determines whether the package is available
# Determines whether a package is available.
#
# @see https://github.com/yast/yast-yast2/blob/b8cd178b7f341f6e3438782cb703f4a3ab0529ed/library/packages/src/modules/Package.rb#L72
# @todo Perform a real D-Bus call.
def Available(_package_name)
true
# @param name [String] Package name.
# @return [Boolean]
def Available(name)
client.package_available?(name)
end

# Determines whether the package is available
# Determines whether a set of packages is available.
#
# @todo Perform a real D-Bus call.
def AvailableAll(_package_names)
true
# @param names [Array<String>] Names of the packages.
# @return [Boolean]
def AvailableAll(names)
names.all? { |name| client.package_available?(name) }
end

# Determines whether the package is available
# Determines whether a package is installed in the target system.
#
# @see https://github.com/yast/yast-yast2/blob/b8cd178b7f341f6e3438782cb703f4a3ab0529ed/library/packages/src/modules/Package.rb#L121
# @todo Perform a real D-Bus call.
def Installed(package_name, target: nil)
client.package_installed?(package_name)
# @param name [String] Package name.
# @return [Boolean]
def Installed(name, target: nil)
client.package_installed?(name)
end

private
Expand Down
13 changes: 11 additions & 2 deletions service/lib/agama/software/manager.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) [2021-2023] SUSE LLC
# Copyright (c) [2021-2024] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -279,14 +279,23 @@ def on_selected_patterns_change(&block)
@selected_patterns_change_callbacks << block
end

# Determines whether a package is installed
# Determines whether a package is installed in the target system.
#
# @param name [String] Package name
# @return [Boolean] true if it is installed; false otherwise
def package_installed?(name)
on_target { Yast::Package.Installed(name, target: :system) }
end

# Determines whether a package is available.
#
# @param name [String] Package name
# @return [Boolean]
def package_available?(name)
# Beware: apart from true and false, Available can return nil if things go wrong.
on_local { !!Yast::Package.Available(name) }
end

# Counts how much disk space installation will use.
# @return [String]
# @note Reimplementation of Yast::Package.CountSizeToBeInstalled
Expand Down
6 changes: 6 additions & 0 deletions service/package/rubygem-agama.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Thu Jan 18 14:55:36 UTC 2024 - José Iván López González <[email protected]>

- Add support to check availability of a package
(gh#openSUSE/agama#1004).

-------------------------------------------------------------------
Thu Jan 18 08:35:01 UTC 2024 - Ancor Gonzalez Sosa <[email protected]>

Expand Down
26 changes: 25 additions & 1 deletion service/test/agama/dbus/clients/software_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) [2022-2023] SUSE LLC
# Copyright (c) [2022-2024] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -164,6 +164,30 @@
end
end

describe "#package_available?" do
let(:dbus_object) do
double(::DBus::ProxyObject, introspect: nil, IsPackageAvailable: available)
end

let(:package) { "NetworkManager" }

context "when the package is available" do
let(:available) { true }

it "returns true" do
expect(subject.package_available?(package)).to eq(true)
end
end

context "when the package is available" do
let(:available) { false }

it "returns false" do
expect(subject.package_available?(package)).to eq(false)
end
end
end

describe "#on_product_selected" do
before do
allow(dbus_product).to receive(:path).and_return("/org/opensuse/Agama/Test")
Expand Down
12 changes: 11 additions & 1 deletion service/test/agama/dbus/software/manager_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) [2022-2023] SUSE LLC
# Copyright (c) [2022-2024] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -135,4 +135,14 @@
expect(installed).to eq(true)
end
end

describe "D-Bus IsPackageAvailable" do
it "returns whether the package is available or not" do
expect(backend).to receive(:package_available?).with("NetworkManager").and_return(true)
available = subject.public_send(
"org.opensuse.Agama.Software1%%IsPackageAvailable", "NetworkManager"
)
expect(available).to eq(true)
end
end
end
34 changes: 33 additions & 1 deletion service/test/agama/software/manager_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) [2022-2023] SUSE LLC
# Copyright (c) [2022-2024] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -406,6 +406,38 @@
end
end

describe "#package_available?" do
before do
allow(Yast::Package).to receive(:Available).with(package).and_return(available)
end

let(:package) { "NetworkManager" }

context "when the package is available" do
let(:available) { true }

it "returns true" do
expect(subject.package_available?(package)).to eq(true)
end
end

context "when the package is not available" do
let(:available) { false }

it "returns false" do
expect(subject.package_available?(package)).to eq(false)
end
end

context "when there is an error checking its availability" do
let(:available) { nil }

it "returns false" do
expect(subject.package_available?(package)).to eq(false)
end
end
end

describe "#product_issues" do
before do
allow_any_instance_of(Agama::Software::ProductBuilder)
Expand Down

0 comments on commit d516f74

Please sign in to comment.