Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions service/lib/agama/dbus/storage/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ def perform_probe
#
# @note Skips if no proposal has been calculated yet.
def configure_with_current
return unless proposal.storage_json
return unless manager.product_config

calculate_proposal(manager.config_json)
# The storage proposal with the current settings is not explicitly requested. It is
Expand All @@ -308,6 +308,21 @@ def calculate_proposal(config_json = nil)
manager.configure(config_json)
manager.add_packages if manager.proposal.success?

# The "return if unchanged" guard has been removed from the methods below to always
# emit the corresponding signal.
#
# Since signals do not carry payloads yet, the UI cannot update the query cache
# directly and must refetch after receiving the signal. Without emitting the signal,
# the related queries are never invalidated and never refetched, leaving the progress
# overlay blocked indefinitely.
#
# The overlay intentionally waits until fresh data arrives before unblocking, since
# data can take time to appear after progress completes. Dismissing it
# earlier would cause flickering and leave users able to interact with stale data.
#
# It can be reverted (and UI progress adapted accordingly) when signals carry payloads
# that allow the UI to update the cache directly, removing the need to wait for a
# refetch as part of progress completion.
update_serialized_config
update_serialized_config_model
update_serialized_proposal
Expand All @@ -324,7 +339,7 @@ def calculate_bootloader
# Updates the system info if needed.
def update_serialized_system
serialized_system = serialize_system
return if self.serialized_system == serialized_system
# return if self.serialized_system == serialized_system

# This assignment emits a D-Bus PropertiesChanged.
self.serialized_system = serialized_system
Expand All @@ -334,7 +349,7 @@ def update_serialized_system
# Updates the config info if needed.
def update_serialized_config
serialized_config = serialize_config
return if self.serialized_config == serialized_config
# return if self.serialized_config == serialized_config

# This assignment emits a D-Bus PropertiesChanged.
self.serialized_config = serialized_config
Expand All @@ -343,7 +358,7 @@ def update_serialized_config
# Updates the config model info if needed.
def update_serialized_config_model
serialized_config_model = serialize_config_model
return if self.serialized_config_model == serialized_config_model
# return if self.serialized_config_model == serialized_config_model

# This assignment emits a D-Bus PropertiesChanged.
self.serialized_config_model = serialized_config_model
Expand All @@ -352,7 +367,7 @@ def update_serialized_config_model
# Updates the proposal info if needed.
def update_serialized_proposal
serialized_proposal = serialize_proposal
return if self.serialized_proposal == serialized_proposal
# return if self.serialized_proposal == serialized_proposal

# This assignment emits a D-Bus PropertiesChanged.
self.serialized_proposal = serialized_proposal
Expand All @@ -362,7 +377,7 @@ def update_serialized_proposal
# Updates the issues info if needed.
def update_serialized_issues
serialized_issues = serialize_issues
return if self.serialized_issues == serialized_issues
# return if self.serialized_issues == serialized_issues

# This assignment emits a D-Bus PropertiesChanged.
self.serialized_issues = serialized_issues
Expand Down
2 changes: 1 addition & 1 deletion service/lib/agama/storage/proposal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ def failed_issue
# @return [Issue]
def exception_issue(error)
Issue.new(
_("A problem ocurred while calculating the storage setup"),
_("A problem occurred while calculating the storage setup"),
kind: IssueClasses::PROPOSAL,
details: error.message
)
Expand Down
7 changes: 7 additions & 0 deletions service/package/rubygem-agama-yast.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Wed Apr 8 09:28:31 UTC 2026 - Knut Anderssen <kanderssen@suse.com>

- Fix for diskless installation making a proposal when
there is at least the product configuration notifying the
system and proposal state (bsc#1260378).
Comment on lines +4 to +6
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NP: Too coupled to the implementation detail, IMHO.

What about just saying in the line of "Always update system and proposal state to avoid progress stalling, even when status hasn’t changed after an action."?

In any case, feel free to keep it as it is.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about just saying in the line of "Always update system and proposal state to avoid progress stalling, even when status hasn’t changed after an action."?

Reading it twice it is kind of coupled as well, and probably "update" is not the right word, but it was just an example for trying to make the changelog entry a bit more for humans. Details are in the code itself and in the bug report. Better to express what it fix/prevents.


-------------------------------------------------------------------
Mon Mar 23 16:29:40 UTC 2026 - Josef Reidinger <jreidinger@suse.com>

Expand Down
50 changes: 27 additions & 23 deletions service/test/agama/dbus/storage/manager_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def parse(string)
let(:drive2) { instance_double(Y2Storage::Disk, name: "/dev/vdb", sid: 96) }
let(:drive3) { instance_double(Y2Storage::Disk, name: "/dev/vdb", sid: 97) }

it "retuns the id of each drive" do
it "returns the id of each drive" do
result = parse(subject.serialized_system)[:availableDrives]
expect(result).to contain_exactly(95, 96, 97)
end
Expand All @@ -254,7 +254,7 @@ def parse(string)
let(:drive1) { instance_double(Y2Storage::Disk, name: "/dev/vda", sid: 95) }
let(:drive2) { instance_double(Y2Storage::Disk, name: "/dev/vdb", sid: 96) }

it "retuns the id of each drive" do
it "returns the id of each drive" do
result = parse(subject.serialized_system)[:candidateDrives]
expect(result).to contain_exactly(95, 96)
end
Expand Down Expand Up @@ -299,7 +299,7 @@ def parse(string)
let(:md_raid1) { instance_double(Y2Storage::Md, name: "/dev/md0", sid: 100) }
let(:md_raid2) { instance_double(Y2Storage::Md, name: "/dev/md1", sid: 101) }

it "retuns the path of each MD RAID" do
it "returns the path of each MD RAID" do
result = parse(subject.serialized_system)[:candidateMdRaids]
expect(result).to contain_exactly(100, 101)
end
Expand All @@ -323,7 +323,7 @@ def parse(string)

let(:drive) { instance_double(Y2Storage::Disk, name: "/dev/vda", sid: 95) }

it "retuns an empty array" do
it "returns an empty array" do
result = parse(subject.serialized_system)[:issues]
expect(result).to eq []
end
Expand Down Expand Up @@ -652,7 +652,7 @@ def parse(string)

include_examples "do not activate or probe"
include_examples "do not update product configuration"
include_examples "do not emit SystemChanged"
include_examples "emit SystemChanged"
include_examples "calculate proposal"
end
end
Expand Down Expand Up @@ -722,15 +722,17 @@ def parse(string)
{
storage: {
drives: [
ptableType: "gpt",
partitions: [
{
filesystem: {
type: "btrfs",
path: "/"
{
ptableType: "gpt",
partitions: [
{
filesystem: {
type: "btrfs",
path: "/"
}
}
}
]
]
}
]
}
}
Expand Down Expand Up @@ -825,7 +827,7 @@ def parse(string)

include_examples "do not activate or probe"
include_examples "do not update product configuration"
include_examples "do not emit SystemChanged"
include_examples "emit SystemChanged"
include_examples "calculate new proposal"
end
end
Expand Down Expand Up @@ -1123,6 +1125,7 @@ def parse(string)
describe "#probe" do
before do
allow(subject).to receive(:SystemChanged)
allow(subject).to receive(:ProposalChanged)
allow(subject).to receive(:ProgressChanged)
allow(subject).to receive(:ProgressFinished)

Expand Down Expand Up @@ -1158,31 +1161,32 @@ def parse(string)
end

context "when no storage configuration has been set" do
it "does not calculate a new proposal" do
expect(backend).to_not receive(:configure)
it "re-calculates the proposal" do
expect(backend).to receive(:configure).with(nil)
subject.probe
end

it "does not configure bootloader" do
expect(bootloader).to_not receive(:configure)
it "configures bootloader" do
expect(bootloader).to receive(:configure)
subject.probe
end

it "does not emit a ProposalChanged signal" do
expect(subject).to_not receive(:ProposalChanged)
it "adjusts the packages to install in the target system" do
allow(proposal).to receive(:success?).and_return(true)
expect(backend).to receive(:add_packages)
subject.probe
end

it "emits signals for SystemChanged, ProgressChanged and ProgressFinished" do
it "emits signals for ProposalChanged, SystemChanged, ProgressChanged and ProgressFinished" do
expect(subject).to receive(:SystemChanged) do |system_str|
system = parse(system_str)
device = system[:devices].first
expect(device[:name]).to eq "/dev/sda"
expect(system[:availableDrives]).to eq [device[:sid]]
end
expect(subject).to receive(:ProposalChanged)
expect(subject).to receive(:ProgressChanged).with(/storage configuration/i)
expect(subject).to receive(:ProgressFinished)

subject.probe
end
end
Expand Down Expand Up @@ -1251,7 +1255,7 @@ def parse(string)
end
end

context "if an agama proposal has been succesfully calculated" do
context "if an agama proposal has been successfully calculated" do
before do
backend.configure(config_json)
end
Expand Down
Loading