Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package rubygem-agama-yast for openSUSE:Factory checked in at 2026-01-30 18:19:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-agama-yast (Old) and /work/SRC/openSUSE:Factory/.rubygem-agama-yast.new.1995 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-agama-yast" Fri Jan 30 18:19:38 2026 rev:35 rq:1329814 version:19.pre.devel1272.5cc4683a6 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-agama-yast/rubygem-agama-yast.changes 2026-01-28 15:06:15.975802671 +0100 +++ /work/SRC/openSUSE:Factory/.rubygem-agama-yast.new.1995/rubygem-agama-yast.changes 2026-01-30 18:20:00.447804908 +0100 @@ -1,0 +2,12 @@ +Thu Jan 29 09:55:38 UTC 2026 - Imobach Gonzalez Sosa <[email protected]> + +- Retry requests to the web server if the connection failed + (gh#agama-project/agama#3096, related to bsc#1257067). + +------------------------------------------------------------------- +Wed Jan 28 09:51:16 UTC 2026 - José Iván López González <[email protected]> + +- Configure storage and iSCSI only if needed + (gh#agama-project/agama#3064). + +------------------------------------------------------------------- Old: ---- agama-yast-19.pre.devel1189.efc3a4978.gem New: ---- agama-yast-19.pre.devel1272.5cc4683a6.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ agama-yast.spec ++++++ --- /var/tmp/diff_new_pack.3udcGh/_old 2026-01-30 18:20:01.927866663 +0100 +++ /var/tmp/diff_new_pack.3udcGh/_new 2026-01-30 18:20:01.931866830 +0100 @@ -17,7 +17,7 @@ Name: agama-yast -Version: 19.pre.devel1189.efc3a4978 +Version: 19.pre.devel1272.5cc4683a6 Release: 0 %define mod_name agama-yast %define mod_full_name %{mod_name}-%{version} ++++++ rubygem-agama-yast.spec ++++++ --- /var/tmp/diff_new_pack.3udcGh/_old 2026-01-30 18:20:02.007870001 +0100 +++ /var/tmp/diff_new_pack.3udcGh/_new 2026-01-30 18:20:02.007870001 +0100 @@ -24,7 +24,7 @@ # Name: rubygem-agama-yast -Version: 19.pre.devel1189.efc3a4978 +Version: 19.pre.devel1272.5cc4683a6 Release: 0 %define mod_name agama-yast %define mod_full_name %{mod_name}-%{version} ++++++ agama-yast-19.pre.devel1189.efc3a4978.gem -> agama-yast-19.pre.devel1272.5cc4683a6.gem ++++++ Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/dbus/storage/iscsi.rb new/lib/agama/dbus/storage/iscsi.rb --- old/lib/agama/dbus/storage/iscsi.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/dbus/storage/iscsi.rb 1980-01-02 01:00:00.000000000 +0100 @@ -87,9 +87,17 @@ def configure(serialized_config) config_json = JSON.parse(serialized_config, symbolize_names: true) + # Do not configure if there is no config + return unless config_json + + # Do not configure if there is nothing to change. + return if manager.configured?(config_json) + + logger.info("Configuring iSCSI") + start_progress(1, _("Configuring iSCSI")) - manager.configure(config_json) - emit_system_changed + system_changed = manager.configure(config_json) + emit_system_changed if system_changed finish_progress end @@ -98,7 +106,10 @@ # @param serialized_options [String] Serialized dicovery options. # @return [Number] 0 success; 1 failure. def discover(serialized_options) + logger.info("Discovering iSCSI targets") + options = JSON.parse(serialized_options, symbolize_names: true) + address = options[:address] port = options[:port] credentials = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/dbus/storage/manager.rb new/lib/agama/dbus/storage/manager.rb --- old/lib/agama/dbus/storage/manager.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/dbus/storage/manager.rb 1980-01-02 01:00:00.000000000 +0100 @@ -169,15 +169,23 @@ # # @raise If the config is not valid. # - # @param serialized_product [String] Serialized product config. + # @param serialized_product_config [String] Serialized product config. # @param serialized_config [String] Serialized storage config. - def configure(serialized_product, serialized_config) + def configure(serialized_product_config, serialized_config) + product_config_json = JSON.parse(serialized_product_config) + config_json = JSON.parse(serialized_config, symbolize_names: true) + + # Do not configure if there is nothing to change. + return if backend.configured?(product_config_json, config_json) + + logger.info("Configuring storage") + system_changed = false - new_product_config = Agama::Config.new(JSON.parse(serialized_product)) + product_config = Agama::Config.new(product_config_json) - if product_config != new_product_config + if backend.product_config != product_config system_changed = true - backend.product_config = new_product_config + backend.update_product_config(product_config) end start_progress(3, ACTIVATING_STEP) @@ -197,8 +205,6 @@ emit_system_changed if system_changed next_progress_step(CONFIGURING_STEP) - config_json = JSON.parse(serialized_config, symbolize_names: true) - calculate_proposal(config_json) finish_progress @@ -307,12 +313,11 @@ # Configures storage using the current config. # - # @note The proposal is not calculated if there is not a config yet. + # @note Skips if no proposal has been calculated yet. def configure_with_current - config_json = proposal.storage_json - return unless config_json + return unless proposal.storage_json - calculate_proposal(config_json) + calculate_proposal(backend.config_json) end # @see #configure diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/http/clients/base.rb new/lib/agama/http/clients/base.rb --- old/lib/agama/http/clients/base.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/http/clients/base.rb 1980-01-02 01:00:00.000000000 +0100 @@ -37,7 +37,9 @@ # @param path [String] path relatived to `api`` endpoint. # @param data [#to_json] data to send in request def post(path, data) - response = Net::HTTP.post(uri(path), data.to_json, headers) + response = request_with_retry do + Net::HTTP.post(uri(path), data.to_json, headers) + end return response unless response.is_a?(Net::HTTPClientError) @logger.warn "server returned #{response.code} with body: #{response.body}" @@ -47,7 +49,9 @@ # @param path [String] path relatived to `api`` endpoint. # @return [Net::HTTPResponse, nil] Net::HTTPResponse if it is not an Net::HTTPClientError def get(path) - response = Net::HTTP.get(uri(path), headers) + response = request_with_retry do + Net::HTTP.get(uri(path), headers) + end return response unless response.is_a?(Net::HTTPClientError) @logger.warn "server returned #{response.code} with body: #{response.body}" @@ -57,7 +61,9 @@ # @param path [String] path relatived to `api`` endpoint. # @param data [#to_json] data to send in request def put(path, data) - response = Net::HTTP.put(uri(path), data.to_json, headers) + response = request_with_retry do + Net::HTTP.put(uri(path), data.to_json, headers) + end return unless response.is_a?(Net::HTTPClientError) @logger.warn "server returned #{response.code} with body: #{response.body}" @@ -68,8 +74,10 @@ # @param data [#to_json] data to send in request def patch(path, data) url = uri(path) - http = Net::HTTP.start(url.hostname, url.port, use_ssl: url.scheme == "https") - response = http.patch(url, data.to_json, headers) + response = request_with_retry do + http = Net::HTTP.start(url.hostname, url.port, use_ssl: url.scheme == "https") + http.patch(url, data.to_json, headers) + end return response unless response.is_a?(Net::HTTPClientError) @logger.warn "server returned #{response.code} with body: #{response.body}" @@ -91,6 +99,29 @@ def auth_token File.read("/run/agama/token") end + + CONNECT_ATTEMPTS = 10 + + # Performs a request and retries if it fails. + # + # During initialization, it might happen that Agama's web server is not available. + # This method retries the block if the connection is not possible. + # + # @return [Object] value returned by the block + def request_with_retry(&block) + attempt = 1 + begin + block.call + rescue Errno::ECONNREFUSED => e + @logger.warn "Failed to contact Agama's server with error #{e} " \ + "(attempt #{attempt} of #{CONNECT_ATTEMPTS})." + raise if attempt == CONNECT_ATTEMPTS + + sleep 1 + attempt += 1 + retry + end + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/storage/iscsi/initiator.rb new/lib/agama/storage/iscsi/initiator.rb --- old/lib/agama/storage/iscsi/initiator.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/storage/iscsi/initiator.rb 1980-01-02 01:00:00.000000000 +0100 @@ -19,11 +19,15 @@ # To contact SUSE LLC about this file by physical or electronic mail, you may # find current contact information at www.suse.com. +require "yast2/equatable" + module Agama module Storage module ISCSI # Class representing an open-iscsi initiator class Initiator + include Yast2::Equatable + # Initiator name # # @return [String] @@ -34,6 +38,8 @@ # @return [Boolean] attr_accessor :ibft_name alias_method :ibft_name?, :ibft_name + + eql_attr :name, :ibft_name end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/storage/iscsi/manager.rb new/lib/agama/storage/iscsi/manager.rb --- old/lib/agama/storage/iscsi/manager.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/storage/iscsi/manager.rb 1980-01-02 01:00:00.000000000 +0100 @@ -86,15 +86,31 @@ # Applies the given iSCSI config. # # @param config_json [Hash{Symbol=>Object}] Config according to the JSON schema. + # @return [Boolean] Whether the iSCSI system was changed. def configure(config_json) probe unless probed? config = assign_config(config_json) + + initiator = self.initiator + nodes = self.nodes + probe_after do configure_initiator(config) discover_from_portals(config) disconnect_missing_targets(config) configure_targets(config) end + + system_changed?(initiator, nodes) + end + + # Whether the system is already configured for the given config. + # + # @param config_json [Hash] + # @return [Boolean] + def configured?(config_json) + config = ConfigImporter.new(config_json).import + initiator_configured?(config) && nodes_configured?(config) end private @@ -147,12 +163,55 @@ @nodes end + # Whether the initiator is already configured for the given config. + # + # @param config [Config] + # @return [Boolean] + def initiator_configured?(config) + return true unless config.initiator + + initiator&.name == config.initiator + end + + # Whether all the nodes are already configured for the given config. + # + # @param config [Config] + # @return [Boolean] + def nodes_configured?(config) + nodes.all? { |n| node_configured?(n, config) } + end + + # Whether the node is already configured for the given config. + # + # @param node [Node] + # @param config [Config] + # + # @return [Boolean] + def node_configured?(node, config) + target_config = config.find_target(node.target) + + if target_config + node.connected? && + !credentials_changed?(target_config) && + !startup_changed?(target_config) + else + !node.connected || node.locked? + end + end + + # Whether the system has changed. + # + # @param initiator [Initiator] + # @param nodes [Array<Node>] + def system_changed?(initiator, nodes) + self.initiator != initiator || self.nodes != nodes + end + # Configures the initiator. # # @param config [ISCSI::Config] def configure_initiator(config) - return unless initiator && config.initiator - return if initiator.name == config.initiator + return if initiator_configured?(config) adapter.update_initiator(initiator, name: config.initiator) end @@ -165,6 +224,7 @@ interfaces = config.interfaces(portal) adapter.discover_from_portal(portal, interfaces: interfaces) end + probe_nodes end # Disconnects the targets that are not configured, preventing to disconnect locked targets. @@ -218,6 +278,7 @@ # # @return [Boolean] Whether the node was connected. def connect_node(node, target_config) + logger.info("Connecting iSCSI node: #{node.inspect}") adapter.login( node, credentials: target_config.credentials || {}, @@ -230,6 +291,7 @@ # @param node [Node] # @return [Boolean] Whether the node was disconnected. def disconnect_node(node) + logger.info("Disconnecting iSCSI node: #{node.inspect}") adapter.logout(node).tap do |success| # Unlock the node if it was correctly disconnected. @locked_targets&.delete(node.target) if success @@ -253,6 +315,7 @@ # # @return [Boolean] Whether the node was updated. def update_node(node, target_config) + logger.info("Updating iSCSI node: #{node.inspect}") adapter.update_node(node, startup: target_config.startup) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/storage/iscsi/node.rb new/lib/agama/storage/iscsi/node.rb --- old/lib/agama/storage/iscsi/node.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/storage/iscsi/node.rb 1980-01-02 01:00:00.000000000 +0100 @@ -19,6 +19,8 @@ # To contact SUSE LLC about this file by physical or electronic mail, you may # find current contact information at www.suse.com. +require "yast2/equatable" + module Agama module Storage module ISCSI @@ -28,6 +30,8 @@ # is a single iSCSI initiator or target. Open-iscsi uses the term node to refer to a portal on # a target class Node + include Yast2::Equatable + # Target IP address # # @return [String] @@ -68,6 +72,8 @@ # @return [Boolean] attr_accessor :locked + eql_attr :address, :port, :target, :interface, :ibft, :connected, :startup, :locked + def locked? !!locked end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/storage/manager.rb new/lib/agama/storage/manager.rb --- old/lib/agama/storage/manager.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/storage/manager.rb 1980-01-02 01:00:00.000000000 +0100 @@ -44,6 +44,9 @@ # @return [Agama::Config] attr_reader :product_config + # @return [Hash, nil] + attr_reader :config_json + # @return [Bootloader] attr_reader :bootloader @@ -56,15 +59,15 @@ @bootloader = Bootloader.new(logger) @issues = [] @yast_no_bls_boot = ENV["YAST_NO_BLS_BOOT"] - self.product_config = Agama::Config.new + update_product_config(Agama::Config.new) end # Assigns a new product config. # - # @param config [Agama::Config] - def product_config=(config) - @product_config = config - proposal.product_config = config + # @param product_config [Agama::Config] + def update_product_config(product_config) + @product_config = product_config + proposal.product_config = product_config configure_no_bls_bootloader end @@ -90,6 +93,16 @@ Y2Storage::StorageManager.instance.probed? end + # Whether the current proposal was already calculated for the given product and config. + # + # @param product_config_json [Hash] + # @param config_json [Hash] + # + # @return [Boolean] + def configured?(product_config_json, config_json) + product_config.data == product_config_json && self.config_json == config_json + end + # Probes the devices. def probe callbacks = Y2Storage::Callbacks::UserProbe.new @@ -102,7 +115,7 @@ # the default config is applied. # @return [Boolean] Whether storage was successfully configured. def configure(config_json = nil) - logger.info("Configuring storage: #{config_json}") + @config_json = config_json result = Configurator.new(proposal).configure(config_json) update_issues result diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/agama/storage/volume_templates_builder.rb new/lib/agama/storage/volume_templates_builder.rb --- old/lib/agama/storage/volume_templates_builder.rb 1980-01-02 01:00:00.000000000 +0100 +++ new/lib/agama/storage/volume_templates_builder.rb 1980-01-02 01:00:00.000000000 +0100 @@ -152,8 +152,7 @@ outline_data = fetch(data, "outline", {}) VolumeOutline.new.tap do |outline| outline.required = fetch(outline_data, "required", false) - outline.filesystems = fetch(outline_data, "filesystems", []) - outline.filesystems.map! { |fs| fs_type(fs) } + outline.filesystems = fetch(outline_data, "filesystems", []).map { |f| fs_type(f) } outline.snapshots_configurable = fetch(outline_data, "snapshots_configurable", false) size = fetch(outline_data, "auto_size", {}) @@ -163,9 +162,9 @@ outline.base_max_size = max if max outline.adjust_by_ram = fetch(size, :adjust_by_ram, false) outline.min_size_fallback_for = Array(fetch(size, :min_fallback_for)) - outline.min_size_fallback_for.map! { |p| cleanpath(p) } + .map { |p| cleanpath(p) } outline.max_size_fallback_for = Array(fetch(size, :max_fallback_for)) - outline.max_size_fallback_for.map! { |p| cleanpath(p) } + .map { |p| cleanpath(p) } assign_snapshots_increment(outline, fetch(size, :snapshots_increment)) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 1980-01-02 01:00:00.000000000 +0100 +++ new/metadata 1980-01-02 01:00:00.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: agama-yast version: !ruby/object:Gem::Version - version: 19.pre.devel1189.efc3a4978 + version: 19.pre.devel1272.5cc4683a6 platform: ruby authors: - YaST Team ++++++ po.tar.bz2 ++++++
