Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
joseivanlopez committed Aug 21, 2024
1 parent c389911 commit f3b0865
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 151 deletions.
160 changes: 27 additions & 133 deletions service/lib/agama/dbus/storage/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,29 +99,21 @@ def probe
# or legacy AutoYaST settings:
# { "storage": ... }
# { "legacyAutoyastStorage": ... }
def apply_storage_config(serialized_config)
config_json = JSON.parse(serialized_config, symbolize_names: true)

# @todo Validate JSON schema.

storage_json = config_json[:storage]
autoyast_json = config_json[:legacyAutoyastStorage]
# @return [Integer] 0 success; 1 error
def apply_config(serialized_config)
logger.info("Setting storage config from D-Bus: #{serialized_config}")

if storage_json
calculate_proposal(storage_json)
elsif autoyast_json
calculate_autoyast_proposal(autoyast_json)
else
raise "Invalid config: #{serialized_config}"
end
config_json = JSON.parse(serialized_config, symbolize_names: true)
proposal.calculate_from_json(config_json)
proposal.success? ? 0 : 1
end

# Serialized storage config. It can contain storage or legacy AutoYaST settings:
# { "storage": ... } vs { "legacyAutoyastStorage": ... }
#
# @return [String]
def serialized_storage_config
JSON.pretty_generate(storage_config)
def recover_config
JSON.pretty_generate(proposal.config_json)
end

def install
Expand All @@ -142,9 +134,9 @@ def deprecated_system
dbus_interface STORAGE_INTERFACE do
dbus_method(:Probe) { probe }
dbus_method(:SetConfig, "in serialized_config:s, out result:u") do |serialized_config|
busy_while { apply_storage_config(serialized_config) }
busy_while { apply_config(serialized_config) }
end
dbus_method(:GetConfig, "out config:s") { serialized_storage_config }
dbus_method(:GetConfig, "out serialized_config:s") { recover_config }
dbus_method(:Install) { install }
dbus_method(:Finish) { finish }
dbus_reader(:deprecated_system, "b")
Expand Down Expand Up @@ -186,10 +178,23 @@ def update_actions
dbus_reader_attr_accessor :actions, "aa{sv}"
end

# @todo Rename as "org.opensuse.Agama.Storage1.Proposal".
PROPOSAL_CALCULATOR_INTERFACE = "org.opensuse.Agama.Storage1.Proposal.Calculator"
private_constant :PROPOSAL_CALCULATOR_INTERFACE

# Calculates a guided proposal.
#
# @param settings_dbus [Hash]
# @return [Integer] 0 success; 1 error
def calculate_guided_proposal(settings_dbus)
logger.info("Calculating guided storage proposal from D-Bus: #{settings_dbus}")

settings = ProposalSettingsConversion.from_dbus(settings_dbus,
config: config, logger: logger)

proposal.calculate_guided(settings)
proposal.success? ? 0 : 1
end

# List of disks available for installation
#
# Each device is represented by an array containing the name of the device and the label to
Expand Down Expand Up @@ -227,39 +232,6 @@ def default_volume(mount_path)
VolumeConversion.to_dbus(volume)
end

module ProposalStrategy
GUIDED = "guided"
AUTOYAST = "autoyast"
end

# Whether a proposal was calculated.
#
# @return [Boolean]
def proposal_calculated?
proposal.calculated?
end

# Proposal result, including information about success, strategy and settings.
#
# @return [Hash] Empty if there is no proposal yet.
def proposal_result
return {} unless proposal.calculated?

if proposal.strategy?(ProposalStrategy::GUIDED)
{
"success" => proposal.success?,
"strategy" => ProposalStrategy::GUIDED,
"settings" => proposal.settings.to_json_settings.to_json
}
else
{
"success" => proposal.success?,
"strategy" => ProposalStrategy::AUTOYAST,
"settings" => proposal.settings.to_json
}
end
end

dbus_interface PROPOSAL_CALCULATOR_INTERFACE do
dbus_reader :available_devices, "ao"

Expand All @@ -275,13 +247,9 @@ def proposal_result
# @todo Receive guided json settings.
#
# result: 0 success; 1 error
dbus_method(:Calculate, "in settings:a{sv}, out result:u") do |settings|
busy_while { calculate_guided_proposal(settings) }
dbus_method(:Calculate, "in settings_dbus:a{sv}, out result:u") do |settings_dbus|
busy_while { calculate_guided_proposal(settings_dbus) }
end

dbus_reader :proposal_calculated?, "b", dbus_name: "Calculated"

dbus_reader :proposal_result, "a{sv}", dbus_name: "Result"
end

ISCSI_INITIATOR_INTERFACE = "org.opensuse.Agama.Storage1.ISCSI.Initiator"
Expand Down Expand Up @@ -384,80 +352,6 @@ def proposal
backend.proposal
end

# Calculates a proposal.
#
# @param settings_json [Hash]
# @return [Integer] 0 success; 1 error
def calculate_proposal(settings_json)
# @todo Do not accept guided settings.
guided_json = settings_json[:guided]

settings = if guided_json
Agama::Storage::ProposalSettings.new_from_json(guided_json, config: config)
end

logger.info(
"Calculating storage proposal from D-Bus.\n " \
"Input settings: #{settings_json}\n" \
"Storage settings: #{settings.inspect}"
)
end

# Calculates a guided proposal.
#
# @param settings_dbus [Hash]
# @return [Integer] 0 success; 1 error
def calculate_guided_proposal(settings_dbus)
settings = ProposalSettingsConversion.from_dbus(settings_dbus,
config: config, logger: logger)

logger.info(
"Calculating guided storage proposal from D-Bus.\n" \
"Input settings: #{settings_dbus}\n" \
"Storage settings: #{proposal_settings.inspect}"
)

success = proposal.calculate_guided(proposal_settings)
success ? 0 : 1
end

# Calculates an AutoYaST proposal.
#
# @param settings_json [Hash] AutoYaST settings.
# @return [Integer] 0 success; 1 error
def calculate_autoyast_proposal(settings_json)
# Ensures keys are strings.
autoyast_settings = JSON.parse(settings_json.to_json)

logger.info(
"Calculating AutoYaST storage proposal from D-Bus.\n" \
"Input settings: #{settings_json}\n" \
"AutoYaST settings: #{autoyast_settings}"
)

success = proposal.calculate_autoyast(autoyast_settings)
success ? 0 : 1
end

# Storage config from the current proposal, if any.
#
# @return [Hash] Storage config according to JSON schema.
def storage_config
if proposal.strategy?(ProposalStrategy::GUIDED)
{
storage: {
guided: proposal.settings.to_json_settings
}
}
elsif proposal.strategy?(ProposalStrategy::AUTOYAST)
{
autoyastLegacyStorage: proposal.settings
}
else
{}
end
end

def register_storage_callbacks
backend.on_issues_change { issues_properties_changed }
backend.on_deprecated_system_change { storage_properties_changed }
Expand Down Expand Up @@ -517,7 +411,7 @@ def export_proposal
@dbus_proposal = nil
end

return unless proposal.strategy?(ProposalStrategy::GUIDED)
return unless proposal.guided?

@dbus_proposal = DBus::Storage::Proposal.new(proposal, logger)
@service.export(@dbus_proposal)
Expand Down
4 changes: 2 additions & 2 deletions service/lib/agama/dbus/storage/proposal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ def initialize(backend, logger)
#
# @return [Hash]
def settings
return {} unless backend.settings
return {} unless backend.guided?

ProposalSettingsConversion.to_dbus(backend.settings)
ProposalSettingsConversion.to_dbus(backend.guided_settings)
end

# List of sorted actions in D-Bus format.
Expand Down
86 changes: 70 additions & 16 deletions service/lib/agama/storage/proposal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
require "agama/issue"
require "agama/storage/actions_generator"
require "agama/storage/proposal_strategies"
require "json"
require "yast"
require "y2storage"

Expand All @@ -31,7 +32,7 @@ module Storage
class Proposal
include Yast::I18n

# @param config [Config] Agama config
# @param config [Agama::Config] Agama config
# @param logger [Logger]
def initialize(config, logger: nil)
textdomain "agama"
Expand Down Expand Up @@ -73,22 +74,36 @@ def available_devices
disk_analyzer&.candidate_disks || []
end

# Settings used to calculate the current proposal.
# Storage config from the current proposal, if any.
#
# The type depends on the kind of proposal, see {#calculate_guided} and {#calculate_autoyast}.
#
# @return [Agama::Storage::ProposalSettings, Array<Hash>]
def settings
return unless calculated?

strategy_object.settings
# @return [Hash] Storage config according to JSON schema.
def config_json
return {} unless calculated?

case proposal.strategy_object
when ProposalStrategies::Guided
{
storage: {
guided: proposal.settings.to_json_settings
}
}
when ProposalStrategies::Agama
# @todo Convert config to JSON if there is no raw config.
raw_config || {}
when ProposalStrategies::Autoyast
raw_config
else
{}
end
end

# Calculates a new guided proposal.
#
# @param settings [Agama::Storage::ProposalSettings] settings to calculate the proposal.
# @return [Boolean] whether the proposal was correctly calculated.
def calculate_guided(settings)
logger.info("Calculating proposal with guided strategy: #{settings.inspect}")
@raw_config = nil
@strategy_object = ProposalStrategies::Guided.new(config, logger, settings)
calculate
end
Expand All @@ -99,10 +114,44 @@ def calculate_guided(settings)
# of the AutoYaST profile
# @return [Boolean] whether the proposal was correctly calculated.
def calculate_autoyast(partitioning)
logger.info("Calculating proposal with autoyast strategy: #{partitioning}")
@raw_config = nil
@strategy_object = ProposalStrategies::Autoyast.new(config, logger, partitioning)
calculate
end

def calculate_agama(config)
# TODO
@raw_config = nil
false
end

# @raise If config is not valid.
# @param config_json [Hash]
def calculate_from_json(config_json)
# @todo Validate JSON schema.
guided_json = config_json.dig(:storage, :guided)
storage_json = config_json[:storage]
autoyast_json = config_json[:legacyAutoyastStorage]

if guided_json
settings = ProposalSettings.new_from_json(guided_json, config: config)
calculate_guided(settings)
elsif storage_json
# config =
# calculate_agama(config)
elsif autoyast_json
# Ensures keys are strings.
partitioning = JSON.parse(autoyast_json.to_json)
calculate_autoyast(partitioning)
else
raise "Invalid storage config: #{config_json}"
end

@raw_config = config_json
success?
end

# Storage actions.
#
# @return [Array<Action>]
Expand All @@ -115,26 +164,31 @@ def actions
ActionsGenerator.new(probed, target).generate
end

# Whether the current proposal was calculated the given strategy (:autoyast or :guided).
#
# @param id [#downcase]
# @return [Boolean]
def strategy?(id)
def guided?
return false unless calculated?

id.downcase.to_sym == strategy_object.id
strategy_object.is?(ProposalStrategies::Guided)
end

def guided_settings
return unless guided?

strategy_object.settings
end

private

# @return [Config]
# @return [Agama::Config]
attr_reader :config

# @return [Logger]
attr_reader :logger

attr_reader :strategy_object

# @return [Hash] JSON config without processing.
attr_reader :raw_config

# Calculates a new proposal.
#
# @return [Boolean] whether the proposal was correctly calculated.
Expand Down
Loading

0 comments on commit f3b0865

Please sign in to comment.